@haiiro/docuflow 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -18
- package/manifest.json +13 -34
- package/package.json +1 -1
- package/src/front-components/docflow-processes.front-component.mjs +27 -27
- package/src/front-components/docflow-processes.front-component.tsx +26 -90
- package/src/front-components/docflow-tasks.front-component.mjs +19 -19
- package/src/front-components/docflow-tasks.front-component.tsx +24 -4
- package/src/front-components/process-steps.front-component.mjs +19 -19
- package/src/front-components/process-steps.front-component.tsx +9 -11
- package/src/logic-functions/hand-out-form-step.logic-function.mjs +6 -1
- package/src/logic-functions/launch-parameters-step.logic-function.mjs +1 -15
- package/src/logic-functions/launch-parameters-step.logic-function.ts +4 -18
- package/src/logic-functions/launch-process.logic-function.mjs +1 -0
- package/src/logic-functions/on-workflow-run-updated.logic-function.mjs +6 -1
- package/src/logic-functions/save-launch-fields.logic-function.mjs +76 -79
- package/src/logic-functions/save-launch-fields.logic-function.ts +9 -9
|
@@ -8,14 +8,14 @@ import { callAppRoute, createRecord, getErrorMessage, listRecords } from 'src/fr
|
|
|
8
8
|
import { useAsync, useDebouncedValue } from 'src/front/hooks/use-async';
|
|
9
9
|
import { DataTable, DocflowRoot, Message, SplitView, TextField, Toolbar } from 'src/front/ui/components';
|
|
10
10
|
import { FormFieldInputs } from 'src/front/ui/form-field-inputs';
|
|
11
|
-
import { FormFieldsBuilder } from 'src/front/ui/form-fields-builder';
|
|
12
11
|
import { restAnd, restEq, restIlike, restIn } from 'src/shared/api/rest-filter.util';
|
|
13
|
-
import { DOCFLOW_SECTION
|
|
12
|
+
import { DOCFLOW_SECTION } from 'src/shared/docflow.constants';
|
|
14
13
|
import { type FormField, type FormValues } from 'src/shared/form/form-field.type';
|
|
15
|
-
import { findMissingRequiredFields
|
|
14
|
+
import { findMissingRequiredFields } from 'src/shared/form/form-fields.util';
|
|
16
15
|
import { logDocflow, logDocflowError } from 'src/shared/log.util';
|
|
17
16
|
import {
|
|
18
17
|
buildLaunchParameters,
|
|
18
|
+
isLaunchableTrigger,
|
|
19
19
|
isLaunchParametersStep,
|
|
20
20
|
parseLaunchFields,
|
|
21
21
|
} from 'src/shared/workflow/launch-step.util';
|
|
@@ -27,9 +27,7 @@ const SEARCH_DEBOUNCE_MS = 300;
|
|
|
27
27
|
const DRAFT_WAIT_ATTEMPTS = 10;
|
|
28
28
|
const DRAFT_WAIT_MS = 400;
|
|
29
29
|
|
|
30
|
-
type
|
|
31
|
-
|
|
32
|
-
type Panel = { kind: 'closed' } | { kind: 'process'; workflowVersionId: string } | { kind: 'new' };
|
|
30
|
+
type Panel = { kind: 'closed' } | { kind: 'process'; workflowVersionId: string };
|
|
33
31
|
|
|
34
32
|
type WorkflowRecord = { id: string; name?: string | null; smbLaunchFields?: unknown };
|
|
35
33
|
type WorkflowVersionRecord = {
|
|
@@ -74,7 +72,7 @@ const loadProcesses = async (searchQuery: string): Promise<DocflowProcess[]> =>
|
|
|
74
72
|
return workflows.flatMap((workflow) => {
|
|
75
73
|
const version = versions.find((candidate) => candidate.workflowId === workflow.id);
|
|
76
74
|
|
|
77
|
-
if (version === undefined || version.trigger
|
|
75
|
+
if (version === undefined || !isLaunchableTrigger(version.trigger)) {
|
|
78
76
|
return [];
|
|
79
77
|
}
|
|
80
78
|
|
|
@@ -178,40 +176,26 @@ const waitForDraft = async (workflowId: string) => {
|
|
|
178
176
|
}
|
|
179
177
|
};
|
|
180
178
|
|
|
181
|
-
const
|
|
179
|
+
const DocflowProcesses = () => {
|
|
182
180
|
const theme = useTheme();
|
|
183
|
-
const [
|
|
184
|
-
const
|
|
185
|
-
const [
|
|
181
|
+
const [searchInput, setSearchInput] = useState('');
|
|
182
|
+
const searchQuery = useDebouncedValue(searchInput, SEARCH_DEBOUNCE_MS);
|
|
183
|
+
const [panel, setPanel] = useState<Panel>({ kind: 'closed' });
|
|
186
184
|
const [isCreating, setIsCreating] = useState(false);
|
|
187
|
-
const
|
|
185
|
+
const { data: processes, loading, error } = useAsync(() => loadProcesses(searchQuery), [searchQuery]);
|
|
186
|
+
const selectedVersionId = panel.kind === 'process' ? panel.workflowVersionId : undefined;
|
|
187
|
+
const selectedProcess = processes?.find((process) => process.workflowVersionId === selectedVersionId);
|
|
188
188
|
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
189
|
+
// As "Создать" of the standard list: a process with a manual trigger in the
|
|
190
|
+
// docflow section, opened in the editor. Launch parameters are set later
|
|
191
|
+
// with the process's "Параметры запуска" command.
|
|
192
192
|
const handleCreate = async () => {
|
|
193
|
-
const launchFields = kind === 'parameters' ? fields : [];
|
|
194
|
-
const fieldsError = getFormFieldsError(launchFields);
|
|
195
|
-
|
|
196
|
-
if (kind === 'parameters' && launchFields.length === 0) {
|
|
197
|
-
setErrorMessage('Добавьте хотя бы одно поле или выберите обычный процесс');
|
|
198
|
-
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (fieldsError !== undefined) {
|
|
203
|
-
setErrorMessage(fieldsError);
|
|
204
|
-
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
193
|
setIsCreating(true);
|
|
209
|
-
|
|
210
|
-
logDocflow('process: create', { kind, fieldCount: launchFields.length });
|
|
194
|
+
logDocflow('process: create');
|
|
211
195
|
|
|
212
196
|
try {
|
|
213
197
|
const workflow = await createRecord<WorkflowRecord>('workflows', {
|
|
214
|
-
name:
|
|
198
|
+
name: 'Новый процесс',
|
|
215
199
|
smbSection: DOCFLOW_SECTION,
|
|
216
200
|
});
|
|
217
201
|
|
|
@@ -220,77 +204,29 @@ const NewProcessForm = () => {
|
|
|
220
204
|
}
|
|
221
205
|
|
|
222
206
|
await waitForDraft(workflow.id);
|
|
223
|
-
await callAppRoute('/docflow/processes/launch-fields', {
|
|
224
|
-
workflowId: workflow.id,
|
|
225
|
-
fields: launchFields,
|
|
226
|
-
});
|
|
207
|
+
await callAppRoute('/docflow/processes/launch-fields', { workflowId: workflow.id, fields: [] });
|
|
227
208
|
await navigate(AppPath.RecordShowPage, {
|
|
228
209
|
objectNameSingular: 'workflow',
|
|
229
210
|
objectRecordId: workflow.id,
|
|
230
211
|
});
|
|
231
212
|
} catch (createError) {
|
|
232
213
|
logDocflowError('process: create failed', createError);
|
|
233
|
-
|
|
214
|
+
await enqueueSnackbar({
|
|
215
|
+
message: getErrorMessage(createError, 'Не удалось создать процесс'),
|
|
216
|
+
variant: 'error',
|
|
217
|
+
});
|
|
234
218
|
} finally {
|
|
235
219
|
setIsCreating(false);
|
|
236
220
|
}
|
|
237
221
|
};
|
|
238
222
|
|
|
239
|
-
const kindButton = (value: ProcessKind, label: string) => (
|
|
240
|
-
<Button
|
|
241
|
-
variant={kind === value ? 'solid' : 'outline'}
|
|
242
|
-
size="sm"
|
|
243
|
-
disabled={isCreating}
|
|
244
|
-
onClick={() => setKind(value)}
|
|
245
|
-
>
|
|
246
|
-
{label}
|
|
247
|
-
</Button>
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
return (
|
|
251
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: theme.spacing[3] }}>
|
|
252
|
-
<TextField label="Название" placeholder="Новый процесс" value={name} onChange={setName} />
|
|
253
|
-
<div style={{ display: 'flex', flexWrap: 'wrap', gap: theme.spacing[2] }}>
|
|
254
|
-
{kindButton('parameters', LAUNCH_PARAMETERS_STEP_NAME)}
|
|
255
|
-
{kindButton('plain', 'Обычный процесс')}
|
|
256
|
-
</div>
|
|
257
|
-
{kind === 'parameters' ? (
|
|
258
|
-
<>
|
|
259
|
-
<Message tone="hint">
|
|
260
|
-
Поля, которые человек заполняет перед запуском. В процессе появится шаг «
|
|
261
|
-
{LAUNCH_PARAMETERS_STEP_NAME}», и следующие шаги берут значения из его переменных.
|
|
262
|
-
</Message>
|
|
263
|
-
<FormFieldsBuilder fields={fields} onChange={setFields} disabled={isCreating} />
|
|
264
|
-
</>
|
|
265
|
-
) : (
|
|
266
|
-
<Message tone="hint">Ручной запуск без параметров. Шаги добавляются в редакторе.</Message>
|
|
267
|
-
)}
|
|
268
|
-
{errorMessage !== undefined && <Message tone="danger">{errorMessage}</Message>}
|
|
269
|
-
<Button variant="solid" size="md" fullWidth loading={isCreating} onClick={() => void handleCreate()}>
|
|
270
|
-
Создать и открыть редактор
|
|
271
|
-
</Button>
|
|
272
|
-
</div>
|
|
273
|
-
);
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const DocflowProcesses = () => {
|
|
277
|
-
const theme = useTheme();
|
|
278
|
-
const [searchInput, setSearchInput] = useState('');
|
|
279
|
-
const searchQuery = useDebouncedValue(searchInput, SEARCH_DEBOUNCE_MS);
|
|
280
|
-
const [panel, setPanel] = useState<Panel>({ kind: 'closed' });
|
|
281
|
-
const { data: processes, loading, error } = useAsync(() => loadProcesses(searchQuery), [searchQuery]);
|
|
282
|
-
const selectedVersionId = panel.kind === 'process' ? panel.workflowVersionId : undefined;
|
|
283
|
-
const selectedProcess = processes?.find((process) => process.workflowVersionId === selectedVersionId);
|
|
284
|
-
|
|
285
223
|
return (
|
|
286
224
|
<DocflowRoot>
|
|
287
225
|
<SplitView
|
|
288
|
-
panelTitle={
|
|
226
|
+
panelTitle={selectedProcess?.name}
|
|
289
227
|
onClosePanel={() => setPanel({ kind: 'closed' })}
|
|
290
228
|
panel={
|
|
291
|
-
|
|
292
|
-
<NewProcessForm />
|
|
293
|
-
) : selectedProcess !== undefined ? (
|
|
229
|
+
selectedProcess !== undefined ? (
|
|
294
230
|
<ProcessLaunchForm
|
|
295
231
|
key={selectedProcess.workflowVersionId}
|
|
296
232
|
process={selectedProcess}
|
|
@@ -310,7 +246,7 @@ const DocflowProcesses = () => {
|
|
|
310
246
|
/>
|
|
311
247
|
</div>
|
|
312
248
|
<div style={{ marginLeft: 'auto' }}>
|
|
313
|
-
<Button variant="solid" size="sm" onClick={() =>
|
|
249
|
+
<Button variant="solid" size="sm" loading={isCreating} onClick={() => void handleCreate()}>
|
|
314
250
|
Создать
|
|
315
251
|
</Button>
|
|
316
252
|
</div>
|
|
@@ -323,7 +259,7 @@ const DocflowProcesses = () => {
|
|
|
323
259
|
{loading && processes === undefined && <Message>Загрузка…</Message>}
|
|
324
260
|
{!loading && error === undefined && processes?.length === 0 && (
|
|
325
261
|
<Message>
|
|
326
|
-
Процессов для запуска нет. Здесь видны опубликованные процессы с ручным запуском и разделом «Документооборот». Параметры запуска задаются
|
|
262
|
+
Процессов для запуска нет. Здесь видны опубликованные процессы с ручным запуском и разделом «Документооборот». Параметры запуска задаются кнопкой «Параметры запуска» вверху процесса.
|
|
327
263
|
</Message>
|
|
328
264
|
)}
|
|
329
265
|
{processes !== undefined && processes.length > 0 && (
|