Skip to content

Commit 54acb67

Browse files
committed
fixes
1 parent 6bd60f5 commit 54acb67

File tree

16 files changed

+589
-172
lines changed

16 files changed

+589
-172
lines changed

.erb/scripts/check-port-in-use.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ detectPort(port, (_err, availablePort) => {
77
if (port !== String(availablePort)) {
88
throw new Error(
99
chalk.whiteBright.bgRed.bold(
10-
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm run dev`,
10+
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=1213 npm run dev`,
1111
),
1212
);
1313
} else {

release/app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "todo-my-app-name",
3-
"version": "1.19.0",
3+
"version": "1.20.0",
44
"description": "Todo my app description",
55
"license": "MIT",
66
"main": "./dist/main/main.js",

src/main/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ function runApp(onQuit, onWindowMade) {
217217
}
218218

219219
await onClose()
220-
await onQuit()
220+
await onQuit?.()
221221
})
222222
})
223223
.catch(console.log)
@@ -248,8 +248,8 @@ function runAppWithoutWindow(onQuit, onReady) {
248248
powerSaveBlocker.stop(powerSaveId)
249249
}
250250
}
251-
await onQuit()
252251
await onClose()
252+
await onQuit?.()
253253

254254
})
255255
})

src/renderer/app/components/ApiIntegrationComponent/ApiIntegrationComponent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const ContentContainer = ({ selectedScraper, hasSingleScraper , enable_cache}: {
2424
)
2525

2626
//@ts-ignore
27-
const defdata = controls.getDefaultData()
27+
const defdata = controls.getParsedControlData(controls.getDefaultData())
2828

2929
const readmeContent = createApiREADME(baseUrl, selectedScraper.scraper_name,hasSingleScraper, defdata, sorts, filters, views, default_sort, selectedScraper.route_path, selectedScraper.max_runs, getApiBasePath(), getRouteAliases()[selectedScraper.scraper_name] ?? [], enable_cache)
3030
return <MarkdownComponent content={readmeContent} />

src/renderer/app/components/InputComponent/InputComponent.tsx

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react'
12
import { EuiButton } from '@elastic/eui/optimize/es/components/button/button';
23
import { EuiButtonEmpty } from '@elastic/eui/optimize/es/components/button/button_empty/button_empty'
34
import { EuiForm } from '@elastic/eui/optimize/es/components/form/form';
@@ -22,6 +23,8 @@ import ListOfTextFields from '../inputs/ListOfTextFields';
2223
import NumberField from '../inputs/NumberField';
2324
import SingleSelect from '../inputs/SingleSelect';
2425
import SearchField from '../inputs/SearchField';
26+
import SearchSingleSelectApi from '../inputs/SearchSingleSelectApi';
27+
import SearchMultiSelectApi from '../inputs/SearchMultiSelectApi';
2528
import SwitchField from '../inputs/SwitchField';
2629
import TextAreaField from '../inputs/TextAreaField';
2730
import TextField from '../inputs/TextField';
@@ -223,7 +226,21 @@ const InputFields = ({
223226
)
224227
break
225228
case 'select':
226-
inputElement = (
229+
const hasSearchMethod = !!(control as any).searchMethod;
230+
inputElement = hasSearchMethod ? (
231+
<SearchSingleSelectApi
232+
controls={controls}
233+
title={disabledMsg}
234+
isDisabled={disabled}
235+
style={{ maxWidth: '400px' }}
236+
name={id}
237+
value={data[id]}
238+
onChange={value => handleInputChange(id, value)}
239+
searchMethod={(control as any).searchMethod}
240+
canCreateOptions={(control as any).canCreateOptions}
241+
data={data}
242+
/>
243+
) : (
227244
<SingleSelect
228245
title={disabledMsg}
229246
isDisabled={disabled}
@@ -232,11 +249,27 @@ const InputFields = ({
232249
options={options}
233250
value={data[id]}
234251
onChange={value => handleInputChange(id, value)}
252+
canCreateOptions={(control as any).canCreateOptions}
235253
/>
236254
)
237255
break
238256
case 'multiSelect':
239-
inputElement = (
257+
const hasMultiSearchMethod = !!(control as any).searchMethod;
258+
inputElement = hasMultiSearchMethod ? (
259+
<SearchMultiSelectApi
260+
controls={controls}
261+
title={disabledMsg}
262+
isDisabled={disabled}
263+
style={{ maxWidth: '400px' }}
264+
name={id}
265+
value={data[id]}
266+
onChange={value => handleInputChange(id, value)}
267+
searchMethod={(control as any).searchMethod}
268+
canCreateOptions={(control as any).canCreateOptions}
269+
canBulkAdd={(control as any).canBulkAdd}
270+
data={data}
271+
/>
272+
) : (
240273
<InputMultiSelect
241274
title={disabledMsg}
242275
isDisabled={disabled}
@@ -245,6 +278,8 @@ const InputFields = ({
245278
options={options}
246279
value={data[id]}
247280
onChange={value => handleInputChange(id, value)}
281+
canCreateOptions={(control as any).canCreateOptions}
282+
canBulkAdd={(control as any).canBulkAdd}
248283
/>
249284
)
250285
break
@@ -510,16 +545,18 @@ const ScraperFormContainer = ({ scrapers, enable_cache }) => {
510545
scraper_name: selectedScraper.scraper_name,
511546
data: cleanedData,
512547
enable_cache: enableCache}).finally(() => setIsSubmitting(false))
513-
const result = response.data
514-
const isarr = Array.isArray(result)
515-
if (isarr && result.length === 0) {
516-
Toast.error('No Tasks were created.')
517-
}else {
518-
const outputId = isarr ? result[0].id : result.id
519-
if (outputId) {
520-
pushToRoute(router, `/tasks/${outputId}`)
521-
} else {
522-
console.error("failed", result)
548+
if (response) {
549+
const result = response.data
550+
const isarr = Array.isArray(result)
551+
if (isarr && result.length === 0) {
552+
Toast.error('No Tasks were created.')
553+
}else {
554+
const outputId = isarr ? result[0].id : result.id
555+
if (outputId) {
556+
pushToRoute(router, `/tasks/${outputId}`)
557+
} else {
558+
console.error("failed", result)
559+
}
523560
}
524561
}
525562
} catch (error:any) {

src/renderer/app/components/Pagination.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EuiPagination } from '@elastic/eui/optimize/es/components/pagination/pa
33
import SingleSelect from './inputs/SingleSelect';
44

55
export function Pagination({ total_pages, activePage, onPageClick }) {
6-
if (total_pages <= 7) {
6+
if (total_pages <= 5) {
77
return <EuiPagination
88
aria-label={'Pagination'}
99
style={{
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { EuiButton } from '@elastic/eui/optimize/es/components/button/button';
2+
import { EuiButtonEmpty } from '@elastic/eui/optimize/es/components/button/button_empty/button_empty';
3+
import { EuiModal } from '@elastic/eui/optimize/es/components/modal/modal';
4+
import { EuiModalBody } from '@elastic/eui/optimize/es/components/modal/modal_body';
5+
import { EuiModalFooter } from '@elastic/eui/optimize/es/components/modal/modal_footer';
6+
import { EuiModalHeader } from '@elastic/eui/optimize/es/components/modal/modal_header';
7+
import { EuiModalHeaderTitle } from '@elastic/eui/optimize/es/components/modal/modal_header_title';
8+
import { useState } from 'react';
9+
import ClickOutside from '../ClickOutside/ClickOutside';
10+
import TextAreaField from './TextAreaField';
11+
import { isUrl } from '../../utils/missc';
12+
13+
function isEmpty(x: any) {
14+
return x === null || x === undefined || (typeof x === "string" && x.trim() === "");
15+
}
16+
17+
export function isNotEmpty(x: any) {
18+
return !isEmpty(x);
19+
}
20+
21+
function stripChars(input: string) {
22+
// Remove " or ' from the start of the string
23+
let result = input.replace(/^[\'\"]+/, '');
24+
// Remove , from the end of the string
25+
result = result.replace(/,$/, '');
26+
// Remove " or ' from the end of the string
27+
result = result.replace(/[\'\"]+$/, '');
28+
return result;
29+
}
30+
31+
function findLink(inputString: string) {
32+
const regex = /http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+/;
33+
const match = inputString.match(regex);
34+
return match ? match[0] : null;
35+
}
36+
37+
export function getLink(string: string) {
38+
if (isUrl(string)) {
39+
return string;
40+
}
41+
return findLink(string);
42+
}
43+
44+
export function parseStringToList(input: string): string[] {
45+
input = input.trim();
46+
47+
// Handle empty string
48+
if (input === '') {
49+
return [];
50+
}
51+
52+
try {
53+
// Try to parse as JSON
54+
const jsonList = JSON.parse(input);
55+
if (Array.isArray(jsonList)) {
56+
return jsonList.map(x => `${x}`.trim());
57+
}
58+
} catch (e) {
59+
const split = input.split(/[\n]+/);
60+
const lines = split.map(s => stripChars(s.trim()).trim()).filter(isNotEmpty);
61+
if (lines.length === 1) {
62+
return lines[0].split(/[,]+/).map((s: string) => stripChars(s.trim()).trim()).filter(isNotEmpty);
63+
} else {
64+
return lines;
65+
}
66+
}
67+
return [];
68+
}
69+
70+
function computeItemsLen(items: string[], islinks: boolean = false) {
71+
let count: number;
72+
if (islinks) {
73+
count = items.map(getLink).filter(x => x !== null).length;
74+
} else {
75+
count = items.filter(isNotEmpty).length;
76+
}
77+
78+
const itemText = islinks ? (count === 1 ? "Link" : "Links") : (count === 1 ? "Item" : "Items");
79+
return (count > 0 ? ` ${count} ` : ' ') + itemText;
80+
}
81+
82+
interface BulkEditModalProps {
83+
closeModal: () => void;
84+
id: string;
85+
value: string[];
86+
onChangeValue: (newValue: string[]) => void;
87+
islinks?: boolean;
88+
}
89+
90+
export default function BulkEditModal({ closeModal, id, value, onChangeValue, islinks = false }: BulkEditModalProps) {
91+
const [modaltext, onChangeModalText] = useState(() => {
92+
if (islinks) {
93+
return value.filter(isNotEmpty).map(getLink).filter(x => x !== null).map(x => x.trim()).join('\n');
94+
} else {
95+
return value.filter(isNotEmpty).map(x => x.trim()).join('\n');
96+
}
97+
});
98+
99+
const placeholder = islinks
100+
? `Paste a list of links in one of the following formats:
101+
- JSON array (e.g., ["https://stackoverflow.com/", "https://apache.org/"])
102+
- Comma separated (e.g., https://stackoverflow.com/, https://apache.org/)
103+
- Newline separated, e.g.
104+
https://stackoverflow.com/
105+
https://apache.org/`
106+
: `Paste a list of items in one of the following formats:
107+
- JSON array (e.g., ["apple", "guava"])
108+
- Comma separated (e.g., apple, guava)
109+
- Newline-separated, e.g.
110+
apple
111+
guava`;
112+
113+
const handleAdd = () => {
114+
let parsed = parseStringToList(modaltext);
115+
116+
if (islinks) {
117+
parsed = parsed.map(getLink).filter(x => x !== null);
118+
}
119+
120+
onChangeValue(parsed);
121+
closeModal();
122+
};
123+
124+
return (
125+
<EuiModal onClose={closeModal}>
126+
<ClickOutside handleClickOutside={closeModal}>
127+
<div style={{ minWidth: 720 }}>
128+
<EuiModalHeader>
129+
<EuiModalHeaderTitle>Paste Items</EuiModalHeaderTitle>
130+
</EuiModalHeader>
131+
<EuiModalBody>
132+
<TextAreaField
133+
rows={12}
134+
placeholder={placeholder}
135+
name={id}
136+
value={modaltext}
137+
onChange={onChangeModalText}
138+
/>
139+
</EuiModalBody>
140+
<EuiModalFooter>
141+
<EuiButtonEmpty onClick={closeModal}>Cancel</EuiButtonEmpty>
142+
<EuiButton onClick={handleAdd}>
143+
{'Add' + computeItemsLen(parseStringToList(modaltext), islinks)}
144+
</EuiButton>
145+
</EuiModalFooter>
146+
</div>
147+
</ClickOutside>
148+
</EuiModal>
149+
);
150+
}
151+
152+

0 commit comments

Comments
 (0)