@haiiro/docuflow 0.0.6 → 0.0.7
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 +16 -13
- package/manifest.json +12 -12
- 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 +24 -89
- 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 +1 -1
- package/src/front-components/process-steps.front-component.tsx +4 -3
- package/src/logic-functions/launch-parameters-step.logic-function.mjs +1 -1
- package/src/logic-functions/launch-process.logic-function.mjs +1 -0
- package/src/logic-functions/save-launch-fields.logic-function.mjs +33 -2
- package/src/logic-functions/save-launch-fields.logic-function.ts +1 -1
|
@@ -8,11 +8,10 @@ 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,
|
|
@@ -27,9 +26,7 @@ const SEARCH_DEBOUNCE_MS = 300;
|
|
|
27
26
|
const DRAFT_WAIT_ATTEMPTS = 10;
|
|
28
27
|
const DRAFT_WAIT_MS = 400;
|
|
29
28
|
|
|
30
|
-
type
|
|
31
|
-
|
|
32
|
-
type Panel = { kind: 'closed' } | { kind: 'process'; workflowVersionId: string } | { kind: 'new' };
|
|
29
|
+
type Panel = { kind: 'closed' } | { kind: 'process'; workflowVersionId: string };
|
|
33
30
|
|
|
34
31
|
type WorkflowRecord = { id: string; name?: string | null; smbLaunchFields?: unknown };
|
|
35
32
|
type WorkflowVersionRecord = {
|
|
@@ -178,40 +175,26 @@ const waitForDraft = async (workflowId: string) => {
|
|
|
178
175
|
}
|
|
179
176
|
};
|
|
180
177
|
|
|
181
|
-
const
|
|
178
|
+
const DocflowProcesses = () => {
|
|
182
179
|
const theme = useTheme();
|
|
183
|
-
const [
|
|
184
|
-
const
|
|
185
|
-
const [
|
|
180
|
+
const [searchInput, setSearchInput] = useState('');
|
|
181
|
+
const searchQuery = useDebouncedValue(searchInput, SEARCH_DEBOUNCE_MS);
|
|
182
|
+
const [panel, setPanel] = useState<Panel>({ kind: 'closed' });
|
|
186
183
|
const [isCreating, setIsCreating] = useState(false);
|
|
187
|
-
const
|
|
184
|
+
const { data: processes, loading, error } = useAsync(() => loadProcesses(searchQuery), [searchQuery]);
|
|
185
|
+
const selectedVersionId = panel.kind === 'process' ? panel.workflowVersionId : undefined;
|
|
186
|
+
const selectedProcess = processes?.find((process) => process.workflowVersionId === selectedVersionId);
|
|
188
187
|
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
188
|
+
// As "Создать" of the standard list: a process with a manual trigger in the
|
|
189
|
+
// docflow section, opened in the editor. Launch parameters are set later
|
|
190
|
+
// with the process's "Параметры запуска" command.
|
|
192
191
|
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
192
|
setIsCreating(true);
|
|
209
|
-
|
|
210
|
-
logDocflow('process: create', { kind, fieldCount: launchFields.length });
|
|
193
|
+
logDocflow('process: create');
|
|
211
194
|
|
|
212
195
|
try {
|
|
213
196
|
const workflow = await createRecord<WorkflowRecord>('workflows', {
|
|
214
|
-
name:
|
|
197
|
+
name: 'Новый процесс',
|
|
215
198
|
smbSection: DOCFLOW_SECTION,
|
|
216
199
|
});
|
|
217
200
|
|
|
@@ -220,77 +203,29 @@ const NewProcessForm = () => {
|
|
|
220
203
|
}
|
|
221
204
|
|
|
222
205
|
await waitForDraft(workflow.id);
|
|
223
|
-
await callAppRoute('/docflow/processes/launch-fields', {
|
|
224
|
-
workflowId: workflow.id,
|
|
225
|
-
fields: launchFields,
|
|
226
|
-
});
|
|
206
|
+
await callAppRoute('/docflow/processes/launch-fields', { workflowId: workflow.id, fields: [] });
|
|
227
207
|
await navigate(AppPath.RecordShowPage, {
|
|
228
208
|
objectNameSingular: 'workflow',
|
|
229
209
|
objectRecordId: workflow.id,
|
|
230
210
|
});
|
|
231
211
|
} catch (createError) {
|
|
232
212
|
logDocflowError('process: create failed', createError);
|
|
233
|
-
|
|
213
|
+
await enqueueSnackbar({
|
|
214
|
+
message: getErrorMessage(createError, 'Не удалось создать процесс'),
|
|
215
|
+
variant: 'error',
|
|
216
|
+
});
|
|
234
217
|
} finally {
|
|
235
218
|
setIsCreating(false);
|
|
236
219
|
}
|
|
237
220
|
};
|
|
238
221
|
|
|
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
222
|
return (
|
|
286
223
|
<DocflowRoot>
|
|
287
224
|
<SplitView
|
|
288
|
-
panelTitle={
|
|
225
|
+
panelTitle={selectedProcess?.name}
|
|
289
226
|
onClosePanel={() => setPanel({ kind: 'closed' })}
|
|
290
227
|
panel={
|
|
291
|
-
|
|
292
|
-
<NewProcessForm />
|
|
293
|
-
) : selectedProcess !== undefined ? (
|
|
228
|
+
selectedProcess !== undefined ? (
|
|
294
229
|
<ProcessLaunchForm
|
|
295
230
|
key={selectedProcess.workflowVersionId}
|
|
296
231
|
process={selectedProcess}
|
|
@@ -310,7 +245,7 @@ const DocflowProcesses = () => {
|
|
|
310
245
|
/>
|
|
311
246
|
</div>
|
|
312
247
|
<div style={{ marginLeft: 'auto' }}>
|
|
313
|
-
<Button variant="solid" size="sm" onClick={() =>
|
|
248
|
+
<Button variant="solid" size="sm" loading={isCreating} onClick={() => void handleCreate()}>
|
|
314
249
|
Создать
|
|
315
250
|
</Button>
|
|
316
251
|
</div>
|
|
@@ -323,7 +258,7 @@ const DocflowProcesses = () => {
|
|
|
323
258
|
{loading && processes === undefined && <Message>Загрузка…</Message>}
|
|
324
259
|
{!loading && error === undefined && processes?.length === 0 && (
|
|
325
260
|
<Message>
|
|
326
|
-
Процессов для запуска нет. Здесь видны опубликованные процессы с ручным запуском и разделом «Документооборот». Параметры запуска задаются
|
|
261
|
+
Процессов для запуска нет. Здесь видны опубликованные процессы с ручным запуском и разделом «Документооборот». Параметры запуска задаются кнопкой «Параметры запуска» вверху процесса.
|
|
327
262
|
</Message>
|
|
328
263
|
)}
|
|
329
264
|
{processes !== undefined && processes.length > 0 && (
|