@haiiro/docuflow 0.0.1 → 0.0.3
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/{.twenty/output/manifest.json → manifest.json} +9 -9
- package/package.json +15 -3
- package/{.twenty/output/src → src}/front-components/docflow-documents.front-component.mjs +24 -24
- package/src/front-components/docflow-documents.front-component.tsx +21 -6
- package/{.twenty/output/src → src}/front-components/docflow-processes.front-component.mjs +18 -18
- package/{.twenty/output/src → src}/front-components/docflow-tasks.front-component.mjs +18 -18
- package/{.twenty/output/src → src}/front-components/process-steps.front-component.mjs +19 -19
- package/src/front-components/process-steps.front-component.tsx +6 -1
- package/{.twenty/output/src → src}/front-components/task-form.front-component.mjs +24 -24
- package/{.twenty/output/src → src}/logic-functions/launch-process.logic-function.mjs +14 -0
- package/src/logic-functions/launch-process.logic-function.ts +5 -0
- package/{.twenty/output/src → src}/logic-functions/save-launch-fields.logic-function.mjs +14 -0
- package/src/logic-functions/save-launch-fields.logic-function.ts +5 -0
- package/.gitignore +0 -43
- package/.nvmrc +0 -1
- package/.oxlintrc.json +0 -37
- package/.twenty/output/README.md +0 -128
- package/.twenty/output/package.json +0 -49
- package/.twenty/output/public/cover.svg +0 -15
- package/.twenty/output/public/logo.svg +0 -9
- package/.twenty/output/src/front-components/docflow-documents.front-component.tsx +0 -516
- package/.twenty/output/src/front-components/docflow-processes.front-component.tsx +0 -266
- package/.twenty/output/src/front-components/docflow-tasks.front-component.tsx +0 -303
- package/.twenty/output/src/front-components/process-steps.front-component.tsx +0 -286
- package/.twenty/output/src/front-components/task-form.front-component.tsx +0 -29
- package/.twenty/output/src/logic-functions/bitrix-app.logic-function.ts +0 -143
- package/.twenty/output/src/logic-functions/bitrix-event.logic-function.ts +0 -54
- package/.twenty/output/src/logic-functions/bitrix-install.logic-function.ts +0 -81
- package/.twenty/output/src/logic-functions/capture-file.logic-function.ts +0 -32
- package/.twenty/output/src/logic-functions/complete-task.logic-function.ts +0 -46
- package/.twenty/output/src/logic-functions/hand-out-form-step.logic-function.ts +0 -30
- package/.twenty/output/src/logic-functions/health-check.ts +0 -31
- package/.twenty/output/src/logic-functions/launch-parameters-step.logic-function.ts +0 -33
- package/.twenty/output/src/logic-functions/launch-process.logic-function.ts +0 -96
- package/.twenty/output/src/logic-functions/notify-bitrix-assignee.logic-function.ts +0 -85
- package/.twenty/output/src/logic-functions/on-attachment-created.logic-function.ts +0 -67
- package/.twenty/output/src/logic-functions/on-task-updated.logic-function.ts +0 -71
- package/.twenty/output/src/logic-functions/on-workflow-run-updated.logic-function.ts +0 -70
- package/.twenty/output/src/logic-functions/save-launch-fields.logic-function.ts +0 -73
- package/.twenty/output/src/logic-functions/save-step-settings.logic-function.ts +0 -90
- package/.twenty/output/src/logic-functions/save-task-form.logic-function.ts +0 -62
- package/.twenty/output/yarn.lock +0 -3292
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +0 -1
- package/dist/tsconfig.spec.tsbuildinfo +0 -1
- package/src/__tests__/api-and-bitrix.test.ts +0 -89
- package/src/__tests__/form-fields.test.ts +0 -73
- package/src/__tests__/launch-parameters.test.ts +0 -75
- package/src/__tests__/step-settings.test.ts +0 -39
- package/src/__tests__/workflow-run.test.ts +0 -113
- package/src/application-config.ts +0 -58
- package/src/fields/company-documents.field.ts +0 -29
- package/src/fields/document-author.field.ts +0 -32
- package/src/fields/document-counterparty.field.ts +0 -32
- package/src/fields/document-folder-child-folders.field.ts +0 -23
- package/src/fields/document-folder-documents.field.ts +0 -24
- package/src/fields/document-folder-parent-folder.field.ts +0 -31
- package/src/fields/document-folder.field.ts +0 -32
- package/src/fields/document-responsible.field.ts +0 -32
- package/src/fields/member-authored-documents.field.ts +0 -29
- package/src/fields/member-responsible-documents.field.ts +0 -29
- package/src/fields/task-form-schema.field.ts +0 -21
- package/src/fields/task-form-values.field.ts +0 -21
- package/src/fields/task-instruction.field.ts +0 -21
- package/src/fields/task-section.field.ts +0 -36
- package/src/fields/task-workflow-run-id.field.ts +0 -21
- package/src/fields/task-workflow-step-id.field.ts +0 -21
- package/src/fields/task-workflow-thread-id.field.ts +0 -21
- package/src/fields/workflow-launch-fields.field.ts +0 -21
- package/src/fields/workflow-section.field.ts +0 -36
- package/src/front/api.ts +0 -56
- package/src/front/format.ts +0 -60
- package/src/front/hooks/use-async.ts +0 -54
- package/src/front/hooks/use-workspace-members.ts +0 -22
- package/src/front/types.ts +0 -48
- package/src/front/ui/components.tsx +0 -436
- package/src/front/ui/form-field-inputs.tsx +0 -187
- package/src/front/ui/form-fields-builder.tsx +0 -183
- package/src/front/ui/task-work-panel.tsx +0 -218
- package/src/navigation-menu-items/docflow.navigation-menu-item.ts +0 -15
- package/src/objects/document-folder.object.ts +0 -80
- package/src/objects/document.object.ts +0 -312
- package/src/page-layouts/docflow.page-layout.ts +0 -86
- package/src/page-layouts/task-docflow.page-layout-tab.ts +0 -36
- package/src/page-layouts/workflow-steps.page-layout-tab.ts +0 -37
- package/src/roles/default-role.ts +0 -21
- package/src/roles/docflow-member.role.ts +0 -23
- package/src/server/bitrix-page.ts +0 -52
- package/src/server/bitrix-portal.ts +0 -67
- package/src/server/document-capture.ts +0 -102
- package/src/server/http-response.ts +0 -18
- package/src/server/launch-step.ts +0 -166
- package/src/server/process-tasks.ts +0 -116
- package/src/server/records.ts +0 -132
- package/src/server/task-completion.ts +0 -100
- package/src/server/workflow-engine.ts +0 -105
- package/src/shared/api/core-graphql.util.ts +0 -98
- package/src/shared/api/object-summaries.ts +0 -79
- package/src/shared/api/rest-filter.util.ts +0 -37
- package/src/shared/api/rest-response.util.ts +0 -43
- package/src/shared/bitrix/bitrix-client.ts +0 -114
- package/src/shared/bitrix/bitrix.type.ts +0 -25
- package/src/shared/bitrix/bitrix.util.ts +0 -139
- package/src/shared/docflow.constants.ts +0 -31
- package/src/shared/documents/attachment-target.util.ts +0 -64
- package/src/shared/engine.ts +0 -11
- package/src/shared/form/form-field-builder.util.ts +0 -122
- package/src/shared/form/form-field.type.ts +0 -23
- package/src/shared/form/form-fields.util.ts +0 -138
- package/src/shared/form/step-settings.util.ts +0 -104
- package/src/shared/workflow/launch-step.util.ts +0 -56
- package/src/shared/workflow/run-target-record.util.ts +0 -70
- package/src/shared/workflow/workflow-run.type.ts +0 -35
- package/src/shared/workflow/workflow-run.util.ts +0 -174
- package/src/universal-identifiers.ts +0 -199
- package/src/views/all-document-folders.view.ts +0 -50
- package/src/views/all-documents.view.ts +0 -91
- package/src/views/documents-by-status.view.ts +0 -76
- package/tsconfig.json +0 -37
- package/tsconfig.spec.json +0 -9
- package/vitest.unit.config.ts +0 -14
- /package/{.twenty/output/front-component-shared-dependencies.mjs → front-component-shared-dependencies.mjs} +0 -0
- /package/{.twenty/output/src → src}/logic-functions/bitrix-app.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/bitrix-event.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/bitrix-install.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/capture-file.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/complete-task.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/hand-out-form-step.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/health-check.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/launch-parameters-step.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/notify-bitrix-assignee.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/on-attachment-created.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/on-task-updated.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/on-workflow-run-updated.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/save-step-settings.logic-function.mjs +0 -0
- /package/{.twenty/output/src → src}/logic-functions/save-task-form.logic-function.mjs +0 -0
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { restAnd, restEq, restIlike, restIn, sanitizeFilterText } from 'src/shared/api/rest-filter.util';
|
|
4
|
-
import { readRestList, readRestRecord } from 'src/shared/api/rest-response.util';
|
|
5
|
-
import { escapeHtml, parseBitrixGrant, parseBitrixRequest } from 'src/shared/bitrix/bitrix.util';
|
|
6
|
-
import { getAttachmentTarget, getDocumentNameFromFile, readFileItems } from 'src/shared/documents/attachment-target.util';
|
|
7
|
-
import { getDocflowEngine } from 'src/shared/engine';
|
|
8
|
-
|
|
9
|
-
describe('REST helpers', () => {
|
|
10
|
-
it('builds filters the REST parser accepts and strips what breaks it', () => {
|
|
11
|
-
expect(restAnd(restEq('smbSection', 'DOCFLOW'), undefined, restIlike('title', "ООО (Ромашка), 'x'"))).toBe(
|
|
12
|
-
"and(smbSection[eq]:'DOCFLOW',title[ilike]:'%ООО Ромашка x%')",
|
|
13
|
-
);
|
|
14
|
-
expect(restIn('origin', ['RECORD', 'PROCESS'])).toBe('origin[in]:["RECORD","PROCESS"]');
|
|
15
|
-
expect(restAnd()).toBeUndefined();
|
|
16
|
-
expect(sanitizeFilterText('a[b]')).toBe('a b');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('reads records under the single key of data', () => {
|
|
20
|
-
expect(readRestList({ data: { tasks: [{ id: '1' }] }, pageInfo: { hasNextPage: true } })).toEqual({
|
|
21
|
-
records: [{ id: '1' }],
|
|
22
|
-
pageInfo: { hasNextPage: true },
|
|
23
|
-
});
|
|
24
|
-
expect(readRestRecord({ data: { createTask: { id: '1' } } })).toEqual({ id: '1' });
|
|
25
|
-
expect(readRestRecord({ errors: [] })).toBeUndefined();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('Bitrix24', () => {
|
|
30
|
-
it('reads an application launch and an event from form fields', () => {
|
|
31
|
-
expect(
|
|
32
|
-
parseBitrixRequest({ rawBody: 'AUTH_ID=a&REFRESH_ID=r&member_id=m', query: { DOMAIN: 'acme.bitrix24.ru' } }),
|
|
33
|
-
).toMatchObject({ authId: 'a', refreshId: 'r', memberId: 'm', domain: 'acme.bitrix24.ru' });
|
|
34
|
-
expect(
|
|
35
|
-
parseBitrixRequest({
|
|
36
|
-
rawBody: 'event=ONAPPUNINSTALL&auth%5Bapplication_token%5D=t&auth%5Bmember_id%5D=m',
|
|
37
|
-
}),
|
|
38
|
-
).toMatchObject({ event: 'ONAPPUNINSTALL', applicationToken: 't', memberId: 'm' });
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('accepts a grant only with an https portal REST address', () => {
|
|
42
|
-
const grant = {
|
|
43
|
-
member_id: 'm',
|
|
44
|
-
access_token: 'a',
|
|
45
|
-
refresh_token: 'r',
|
|
46
|
-
expires_in: 3600,
|
|
47
|
-
client_endpoint: 'https://acme.bitrix24.ru/rest/',
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
expect(parseBitrixGrant(grant, 0)).toMatchObject({
|
|
51
|
-
memberId: 'm',
|
|
52
|
-
portalDomain: 'acme.bitrix24.ru',
|
|
53
|
-
expiresAt: 3_600_000,
|
|
54
|
-
});
|
|
55
|
-
expect(parseBitrixGrant({ ...grant, client_endpoint: 'http://evil/rest/' }, 0)).toBeUndefined();
|
|
56
|
-
expect(parseBitrixGrant({ ...grant, client_endpoint: 'https://a.ru/rest/?x=1' }, 0)).toBeUndefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('escapes what goes into the portal page', () => {
|
|
60
|
-
expect(escapeHtml('<b>"Акт"</b>')).toBe('<b>"Акт"</b>');
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('documents', () => {
|
|
65
|
-
it('finds the record an attachment belongs to', () => {
|
|
66
|
-
expect(getAttachmentTarget({ authorId: 'a', targetTaskId: null, targetCompanyId: 'c' })).toEqual({
|
|
67
|
-
objectNameSingular: 'company',
|
|
68
|
-
recordId: 'c',
|
|
69
|
-
});
|
|
70
|
-
expect(getAttachmentTarget({ targetMyDealId: 'd' })).toEqual({ objectNameSingular: 'myDeal', recordId: 'd' });
|
|
71
|
-
expect(getAttachmentTarget({ authorId: 'a' })).toBeUndefined();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('reads files and names a document after its file', () => {
|
|
75
|
-
expect(readFileItems([{ fileId: 'f', label: 'Акт.pdf', url: 'u' }, { fileId: '' }])).toEqual([
|
|
76
|
-
{ fileId: 'f', label: 'Акт.pdf', url: 'u' },
|
|
77
|
-
]);
|
|
78
|
-
expect(getDocumentNameFromFile('Договор 12.pdf')).toBe('Договор 12');
|
|
79
|
-
expect(getDocumentNameFromFile('.env')).toBe('.env');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('engine', () => {
|
|
84
|
-
it('runs on the app unless the fork is named', () => {
|
|
85
|
-
expect(getDocflowEngine(undefined)).toBe('APP');
|
|
86
|
-
expect(getDocflowEngine('FORK')).toBe('FORK');
|
|
87
|
-
expect(getDocflowEngine('fork')).toBe('APP');
|
|
88
|
-
});
|
|
89
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { type FormField } from 'src/shared/form/form-field.type';
|
|
4
|
-
import {
|
|
5
|
-
buildFormStepResponse,
|
|
6
|
-
buildFormValues,
|
|
7
|
-
findMissingRequiredFields,
|
|
8
|
-
getFormFieldsError,
|
|
9
|
-
isFormValueEmpty,
|
|
10
|
-
parseFormFields,
|
|
11
|
-
} from 'src/shared/form/form-fields.util';
|
|
12
|
-
|
|
13
|
-
const amount: FormField = {
|
|
14
|
-
id: 'f1',
|
|
15
|
-
name: 'amount',
|
|
16
|
-
label: 'Сумма',
|
|
17
|
-
type: 'NUMBER',
|
|
18
|
-
settings: { smbIsRequired: true },
|
|
19
|
-
};
|
|
20
|
-
const city: FormField = { id: 'f2', name: 'city', label: 'Город', type: 'TEXT', value: 'Пенза' };
|
|
21
|
-
const approver: FormField = {
|
|
22
|
-
id: 'f3',
|
|
23
|
-
name: 'approver',
|
|
24
|
-
label: 'Согласует',
|
|
25
|
-
type: 'RECORD',
|
|
26
|
-
value: '{{trigger.workspaceMemberId}}',
|
|
27
|
-
settings: { smbRole: 'ASSIGNEE', smbIsRequired: true },
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
describe('form fields', () => {
|
|
31
|
-
it('treats blank text, empty lists and a record without id as empty', () => {
|
|
32
|
-
expect(isFormValueEmpty(' ')).toBe(true);
|
|
33
|
-
expect(isFormValueEmpty([])).toBe(true);
|
|
34
|
-
expect(isFormValueEmpty({ id: '' })).toBe(true);
|
|
35
|
-
expect(isFormValueEmpty(0)).toBe(false);
|
|
36
|
-
expect(isFormValueEmpty({ id: 'x' })).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('names empty required fields a person fills, never service fields', () => {
|
|
40
|
-
expect(
|
|
41
|
-
findMissingRequiredFields({ fields: [amount, city, approver], values: {} }).map(
|
|
42
|
-
({ name }) => name,
|
|
43
|
-
),
|
|
44
|
-
).toEqual(['amount']);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('builds values from typed and preset values of fillable fields', () => {
|
|
48
|
-
expect(buildFormValues({ fields: [amount, city, approver], values: { amount: 5 } })).toEqual({
|
|
49
|
-
amount: 5,
|
|
50
|
-
city: 'Пенза',
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('answers a step with every field, service ones included', () => {
|
|
55
|
-
expect(
|
|
56
|
-
buildFormStepResponse({
|
|
57
|
-
fields: [amount, { ...approver, value: { id: 'member-1' } }],
|
|
58
|
-
values: { amount: 7 },
|
|
59
|
-
}),
|
|
60
|
-
).toEqual({ amount: 7, approver: { id: 'member-1' } });
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('rejects repeated and malformed field names', () => {
|
|
64
|
-
expect(getFormFieldsError([amount, amount])).toContain('повторяется');
|
|
65
|
-
expect(getFormFieldsError([{ ...amount, name: '1st' }])).toContain('латинской');
|
|
66
|
-
expect(getFormFieldsError([amount, city])).toBeUndefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('keeps only well-formed fields from stored JSON', () => {
|
|
70
|
-
expect(parseFormFields([amount, { name: 'x' }, null, 'text'])).toEqual([amount]);
|
|
71
|
-
expect(parseFormFields({ fields: [] })).toEqual([]);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { type FormField } from 'src/shared/form/form-field.type';
|
|
4
|
-
import {
|
|
5
|
-
applyBuilderFieldKind,
|
|
6
|
-
buildFieldNameFromLabel,
|
|
7
|
-
buildFieldsOutputSchema,
|
|
8
|
-
buildUniqueFieldName,
|
|
9
|
-
getBuilderFieldKind,
|
|
10
|
-
} from 'src/shared/form/form-field-builder.util';
|
|
11
|
-
import {
|
|
12
|
-
buildLaunchParameters,
|
|
13
|
-
findLaunchParametersStep,
|
|
14
|
-
} from 'src/shared/workflow/launch-step.util';
|
|
15
|
-
|
|
16
|
-
const contract: FormField = { id: 'f1', name: 'contract', label: 'Договор', type: 'TEXT' };
|
|
17
|
-
const manager: FormField = {
|
|
18
|
-
id: 'f2',
|
|
19
|
-
name: 'manager',
|
|
20
|
-
label: 'Руководитель',
|
|
21
|
-
type: 'RECORD',
|
|
22
|
-
settings: { objectName: 'workspaceMember' },
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
describe('launch parameters', () => {
|
|
26
|
-
it('names a field after its label in latin letters', () => {
|
|
27
|
-
expect(buildFieldNameFromLabel('Сумма договора')).toBe('summaDogovora');
|
|
28
|
-
expect(buildFieldNameFromLabel('2 подписи')).toBe('field2Podpisi');
|
|
29
|
-
expect(buildUniqueFieldName('Сумма', ['summa', 'summa2'])).toBe('summa3');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('switches a field between the builder kinds', () => {
|
|
33
|
-
const company = applyBuilderFieldKind(manager, 'COMPANY');
|
|
34
|
-
|
|
35
|
-
expect(company.settings).toEqual({ objectName: 'company' });
|
|
36
|
-
expect(getBuilderFieldKind(company)).toBe('COMPANY');
|
|
37
|
-
expect(getBuilderFieldKind(applyBuilderFieldKind(company, 'DATE'))).toBe('DATE');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('sends every parameter, an empty one as null', () => {
|
|
41
|
-
expect(
|
|
42
|
-
buildLaunchParameters({ fields: [contract, manager], values: { contract: '', manager: { id: 'm' } } }),
|
|
43
|
-
).toEqual({ contract: null, manager: { id: 'm' } });
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('describes the parameters as variables of the step', () => {
|
|
47
|
-
expect(buildFieldsOutputSchema([contract, manager])).toEqual({
|
|
48
|
-
contract: { isLeaf: true, type: 'string', label: 'Договор', value: null },
|
|
49
|
-
manager: {
|
|
50
|
-
isLeaf: false,
|
|
51
|
-
type: 'object',
|
|
52
|
-
label: 'Руководитель',
|
|
53
|
-
value: { id: { isLeaf: true, type: 'string', label: 'Id', value: null } },
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('finds the launch step by the parameters it takes', () => {
|
|
59
|
-
const launchStep = {
|
|
60
|
-
id: 'launch',
|
|
61
|
-
name: 'Запуск с параметрами',
|
|
62
|
-
type: 'LOGIC_FUNCTION',
|
|
63
|
-
settings: {
|
|
64
|
-
input: {
|
|
65
|
-
logicFunctionId: 'fn',
|
|
66
|
-
logicFunctionInput: { parameters: '{{trigger.smbDocflowParameters}}' },
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
const codeStep = { ...launchStep, id: 'code', settings: { input: { logicFunctionInput: {} } } };
|
|
71
|
-
|
|
72
|
-
expect(findLaunchParametersStep([codeStep, launchStep])?.id).toBe('launch');
|
|
73
|
-
expect(findLaunchParametersStep([codeStep])).toBeUndefined();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { type FormField } from 'src/shared/form/form-field.type';
|
|
4
|
-
import { applyStepSettings, readStepSettings } from 'src/shared/form/step-settings.util';
|
|
5
|
-
|
|
6
|
-
const amount: FormField = { id: 'f1', name: 'amount', label: 'Сумма', type: 'NUMBER' };
|
|
7
|
-
const createId = () => 'new-id';
|
|
8
|
-
|
|
9
|
-
describe('step settings', () => {
|
|
10
|
-
it('writes the assignee, the deadline and the required marks into the fields', () => {
|
|
11
|
-
const fields = applyStepSettings({
|
|
12
|
-
fields: [amount],
|
|
13
|
-
settings: { assignee: 'member-1', dueInDays: 2, requiredFieldIds: ['f1'] },
|
|
14
|
-
createId,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
expect(readStepSettings(fields)).toEqual({
|
|
18
|
-
assignee: 'member-1',
|
|
19
|
-
dueInDays: 2,
|
|
20
|
-
requiredFieldIds: ['f1'],
|
|
21
|
-
});
|
|
22
|
-
expect(fields.find(({ id }) => id === 'f1')?.settings).toEqual({ smbIsRequired: true });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('removes the role fields and the required marks when cleared', () => {
|
|
26
|
-
const configured = applyStepSettings({
|
|
27
|
-
fields: [amount],
|
|
28
|
-
settings: { assignee: 'member-1', dueInDays: 2, requiredFieldIds: ['f1'] },
|
|
29
|
-
createId,
|
|
30
|
-
});
|
|
31
|
-
const cleared = applyStepSettings({
|
|
32
|
-
fields: configured,
|
|
33
|
-
settings: { assignee: null, dueInDays: null, requiredFieldIds: [] },
|
|
34
|
-
createId,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(cleared).toEqual([{ ...amount, settings: {} }]);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { getRunTargetRecord } from 'src/shared/workflow/run-target-record.util';
|
|
4
|
-
import { type WorkflowRunState } from 'src/shared/workflow/workflow-run.type';
|
|
5
|
-
import {
|
|
6
|
-
getFormStepTaskRequests,
|
|
7
|
-
resolveStepVariable,
|
|
8
|
-
} from 'src/shared/workflow/workflow-run.util';
|
|
9
|
-
|
|
10
|
-
const MANAGER_ID = '22222222-2222-4222-8222-222222222222';
|
|
11
|
-
const STARTER_ID = '55555555-5555-4555-8555-555555555555';
|
|
12
|
-
const DEAL_ID = '33333333-3333-4333-8333-333333333333';
|
|
13
|
-
const NOW = new Date('2026-10-15T10:00:00.000Z');
|
|
14
|
-
|
|
15
|
-
const parametersStep = {
|
|
16
|
-
id: 'parameters',
|
|
17
|
-
name: 'Параметры',
|
|
18
|
-
type: 'FORM',
|
|
19
|
-
settings: { input: [{ id: 'p1', name: 'manager', label: 'Руководитель', type: 'RECORD' }] },
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const approveStep = {
|
|
23
|
-
id: 'approve',
|
|
24
|
-
name: 'Согласовать',
|
|
25
|
-
type: 'FORM',
|
|
26
|
-
settings: {
|
|
27
|
-
input: [
|
|
28
|
-
{ id: 'f1', name: 'amount', label: 'Сумма', type: 'NUMBER', settings: { smbIsRequired: true } },
|
|
29
|
-
{
|
|
30
|
-
id: 'f2',
|
|
31
|
-
name: 'assignee',
|
|
32
|
-
label: 'Исполнитель',
|
|
33
|
-
type: 'RECORD',
|
|
34
|
-
value: '{{parameters.manager}}',
|
|
35
|
-
settings: { smbRole: 'ASSIGNEE' },
|
|
36
|
-
},
|
|
37
|
-
{ id: 'f3', name: 'due', label: 'Срок', type: 'DATE', settings: { smbRole: 'DUE_AT', smbDueInDays: 2 } },
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const buildState = (approveInfo: object): WorkflowRunState => ({
|
|
43
|
-
flow: {
|
|
44
|
-
trigger: { type: 'MANUAL', nextStepIds: ['parameters'] },
|
|
45
|
-
steps: [parametersStep, approveStep],
|
|
46
|
-
},
|
|
47
|
-
stepInfos: {
|
|
48
|
-
trigger: { status: 'SUCCESS', result: { smbDocflowParameters: { manager: { id: MANAGER_ID } } } },
|
|
49
|
-
parameters: { status: 'SUCCESS', result: { manager: { id: MANAGER_ID } } },
|
|
50
|
-
approve: approveInfo,
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe('workflow run', () => {
|
|
55
|
-
it('reads a variable from what an earlier step returned', () => {
|
|
56
|
-
const { stepInfos } = buildState({});
|
|
57
|
-
|
|
58
|
-
expect(resolveStepVariable('{{parameters.manager}}', stepInfos)).toEqual({ id: MANAGER_ID });
|
|
59
|
-
expect(resolveStepVariable('{{parameters.missing.id}}', stepInfos)).toBeUndefined();
|
|
60
|
-
expect(resolveStepVariable('Привет {{x}}', stepInfos)).toBe('Привет {{x}}');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('hands a waiting step out to the assignee picked at launch', () => {
|
|
64
|
-
const [request] = getFormStepTaskRequests({
|
|
65
|
-
state: buildState({ status: 'PENDING', threadId: 'thread-1' }),
|
|
66
|
-
runStarterWorkspaceMemberId: STARTER_ID,
|
|
67
|
-
now: NOW,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(request).toMatchObject({
|
|
71
|
-
stepId: 'approve',
|
|
72
|
-
threadId: 'thread-1',
|
|
73
|
-
assigneeWorkspaceMemberId: MANAGER_ID,
|
|
74
|
-
dueAt: '2026-10-17T10:00:00.000Z',
|
|
75
|
-
});
|
|
76
|
-
expect(request.fields.map(({ name }) => name)).toEqual(['amount']);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('gives an unassigned step of a manual run to the starter, even the first one', () => {
|
|
80
|
-
const state: WorkflowRunState = {
|
|
81
|
-
flow: { trigger: { type: 'MANUAL', nextStepIds: ['parameters'] }, steps: [parametersStep] },
|
|
82
|
-
stepInfos: { parameters: { status: 'PENDING', threadId: 't' } },
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
expect(
|
|
86
|
-
getFormStepTaskRequests({ state, runStarterWorkspaceMemberId: STARTER_ID, now: NOW }),
|
|
87
|
-
).toMatchObject([{ stepId: 'parameters', assigneeWorkspaceMemberId: STARTER_ID }]);
|
|
88
|
-
expect(
|
|
89
|
-
getFormStepTaskRequests({
|
|
90
|
-
state: { ...state, flow: { ...state.flow, trigger: { type: 'CRON' } } },
|
|
91
|
-
runStarterWorkspaceMemberId: STARTER_ID,
|
|
92
|
-
now: NOW,
|
|
93
|
-
}),
|
|
94
|
-
).toEqual([]);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('skips a step that is answered or not opened yet', () => {
|
|
98
|
-
for (const info of [{ status: 'SUCCESS', threadId: 't' }, { status: 'PENDING' }]) {
|
|
99
|
-
expect(
|
|
100
|
-
getFormStepTaskRequests({ state: buildState(info), runStarterWorkspaceMemberId: null, now: NOW }),
|
|
101
|
-
).toEqual([]);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('links a task of a deal event to that deal', () => {
|
|
106
|
-
expect(
|
|
107
|
-
getRunTargetRecord({
|
|
108
|
-
flow: { trigger: { type: 'DATABASE_EVENT', settings: { eventName: 'opportunity.created' } } },
|
|
109
|
-
stepInfos: { trigger: { result: { recordId: DEAL_ID } } },
|
|
110
|
-
}),
|
|
111
|
-
).toEqual({ targetFieldName: 'targetOpportunityId', recordId: DEAL_ID });
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { defineApplication, FieldType } from 'twenty-sdk/define';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
BITRIX_CLIENT_ID_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
5
|
-
BITRIX_CLIENT_SECRET_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
6
|
-
CRM_PUBLIC_URL_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
7
|
-
DOCFLOW_ENGINE_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
8
|
-
} from 'src/universal-identifiers';
|
|
9
|
-
|
|
10
|
-
// The same identifier stands in the fork's module manifest
|
|
11
|
-
// (twenty-front/src/modules/smb-docflow/manifest.ts): one application, whether
|
|
12
|
-
// it runs on the NorDiv server or on its own.
|
|
13
|
-
export const APPLICATION_UNIVERSAL_IDENTIFIER =
|
|
14
|
-
'0b7d5d2e-8c4f-4a59-9a43-2f6f1c3e9d21';
|
|
15
|
-
|
|
16
|
-
export default defineApplication({
|
|
17
|
-
universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
|
18
|
-
displayName: 'Документооборот',
|
|
19
|
-
description:
|
|
20
|
-
'Задания с полями для заполнения, процессы с запуском по параметрам, документы со всех записей, приложение Битрикс24',
|
|
21
|
-
author: 'NorDiv',
|
|
22
|
-
logo: 'public/logo.svg',
|
|
23
|
-
galleryImages: ['public/cover.svg'],
|
|
24
|
-
applicationVariables: {
|
|
25
|
-
DOCFLOW_ENGINE: {
|
|
26
|
-
universalIdentifier: DOCFLOW_ENGINE_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
27
|
-
label: 'Кто выполняет серверную работу',
|
|
28
|
-
description:
|
|
29
|
-
'APP — серверную работу делают функции приложения. FORK — её делает сервер NorDiv; функции приложения тогда ничего не делают, чтобы не было двойной работы.',
|
|
30
|
-
type: FieldType.SELECT,
|
|
31
|
-
options: [
|
|
32
|
-
{ label: 'Функции приложения', value: 'APP' },
|
|
33
|
-
{ label: 'Сервер NorDiv', value: 'FORK' },
|
|
34
|
-
],
|
|
35
|
-
value: 'APP',
|
|
36
|
-
isSecret: false,
|
|
37
|
-
},
|
|
38
|
-
CRM_PUBLIC_URL: {
|
|
39
|
-
universalIdentifier: CRM_PUBLIC_URL_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
40
|
-
label: 'Адрес CRM компании',
|
|
41
|
-
description:
|
|
42
|
-
'Например https://acme.example.ru — ссылки из Битрикс24 ведут сюда.',
|
|
43
|
-
isSecret: false,
|
|
44
|
-
},
|
|
45
|
-
BITRIX_CLIENT_ID: {
|
|
46
|
-
universalIdentifier: BITRIX_CLIENT_ID_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
47
|
-
label: 'Битрикс24: код приложения (client_id)',
|
|
48
|
-
description: 'Из карточки локального приложения на портале.',
|
|
49
|
-
isSecret: false,
|
|
50
|
-
},
|
|
51
|
-
BITRIX_CLIENT_SECRET: {
|
|
52
|
-
universalIdentifier: BITRIX_CLIENT_SECRET_VARIABLE_UNIVERSAL_IDENTIFIER,
|
|
53
|
-
label: 'Битрикс24: ключ приложения (client_secret)',
|
|
54
|
-
description: 'Из карточки локального приложения на портале.',
|
|
55
|
-
isSecret: true,
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FieldType,
|
|
3
|
-
RelationType,
|
|
4
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
|
5
|
-
defineField,
|
|
6
|
-
} from 'twenty-sdk/define';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
COMPANY_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
10
|
-
DOCUMENT_COUNTERPARTY_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
} from 'src/universal-identifiers';
|
|
13
|
-
|
|
14
|
-
export default defineField({
|
|
15
|
-
universalIdentifier: COMPANY_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
16
|
-
objectUniversalIdentifier:
|
|
17
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
|
|
18
|
-
type: FieldType.RELATION,
|
|
19
|
-
name: 'smbDocuments',
|
|
20
|
-
label: 'Документы',
|
|
21
|
-
icon: 'IconFiles',
|
|
22
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
23
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
24
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
25
|
-
DOCUMENT_COUNTERPARTY_UNIVERSAL_IDENTIFIER,
|
|
26
|
-
universalSettings: {
|
|
27
|
-
relationType: RelationType.ONE_TO_MANY,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FieldType,
|
|
3
|
-
OnDeleteAction,
|
|
4
|
-
RelationType,
|
|
5
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
|
6
|
-
defineField,
|
|
7
|
-
} from 'twenty-sdk/define';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
DOCUMENT_AUTHOR_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
MEMBER_AUTHORED_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
13
|
-
} from 'src/universal-identifiers';
|
|
14
|
-
|
|
15
|
-
export default defineField({
|
|
16
|
-
universalIdentifier: DOCUMENT_AUTHOR_UNIVERSAL_IDENTIFIER,
|
|
17
|
-
objectUniversalIdentifier: DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
18
|
-
type: FieldType.RELATION,
|
|
19
|
-
name: 'author',
|
|
20
|
-
label: 'Автор',
|
|
21
|
-
icon: 'IconUser',
|
|
22
|
-
isNullable: true,
|
|
23
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
24
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workspaceMember.universalIdentifier,
|
|
25
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
26
|
-
MEMBER_AUTHORED_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
27
|
-
universalSettings: {
|
|
28
|
-
relationType: RelationType.MANY_TO_ONE,
|
|
29
|
-
onDelete: OnDeleteAction.SET_NULL,
|
|
30
|
-
joinColumnName: 'authorId',
|
|
31
|
-
},
|
|
32
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FieldType,
|
|
3
|
-
OnDeleteAction,
|
|
4
|
-
RelationType,
|
|
5
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
|
6
|
-
defineField,
|
|
7
|
-
} from 'twenty-sdk/define';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
COMPANY_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
DOCUMENT_COUNTERPARTY_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
13
|
-
} from 'src/universal-identifiers';
|
|
14
|
-
|
|
15
|
-
export default defineField({
|
|
16
|
-
universalIdentifier: DOCUMENT_COUNTERPARTY_UNIVERSAL_IDENTIFIER,
|
|
17
|
-
objectUniversalIdentifier: DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
18
|
-
type: FieldType.RELATION,
|
|
19
|
-
name: 'counterparty',
|
|
20
|
-
label: 'Контрагент',
|
|
21
|
-
icon: 'IconBuildingSkyscraper',
|
|
22
|
-
isNullable: true,
|
|
23
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
24
|
-
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
|
|
25
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
26
|
-
COMPANY_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
27
|
-
universalSettings: {
|
|
28
|
-
relationType: RelationType.MANY_TO_ONE,
|
|
29
|
-
onDelete: OnDeleteAction.SET_NULL,
|
|
30
|
-
joinColumnName: 'counterpartyId',
|
|
31
|
-
},
|
|
32
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { FieldType, RelationType, defineField } from 'twenty-sdk/define';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
DOCUMENT_FOLDER_CHILD_FOLDERS_UNIVERSAL_IDENTIFIER,
|
|
5
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
6
|
-
DOCUMENT_FOLDER_PARENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
7
|
-
} from 'src/universal-identifiers';
|
|
8
|
-
|
|
9
|
-
export default defineField({
|
|
10
|
-
universalIdentifier: DOCUMENT_FOLDER_CHILD_FOLDERS_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
objectUniversalIdentifier: DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
type: FieldType.RELATION,
|
|
13
|
-
name: 'childFolders',
|
|
14
|
-
label: 'Вложенные папки',
|
|
15
|
-
icon: 'IconFolders',
|
|
16
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
17
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
18
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
19
|
-
DOCUMENT_FOLDER_PARENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
20
|
-
universalSettings: {
|
|
21
|
-
relationType: RelationType.ONE_TO_MANY,
|
|
22
|
-
},
|
|
23
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { FieldType, RelationType, defineField } from 'twenty-sdk/define';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
DOCUMENT_FOLDER_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
5
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
6
|
-
DOCUMENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
7
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
8
|
-
} from 'src/universal-identifiers';
|
|
9
|
-
|
|
10
|
-
export default defineField({
|
|
11
|
-
universalIdentifier: DOCUMENT_FOLDER_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
objectUniversalIdentifier: DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
13
|
-
type: FieldType.RELATION,
|
|
14
|
-
name: 'documents',
|
|
15
|
-
label: 'Документы',
|
|
16
|
-
icon: 'IconFiles',
|
|
17
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
18
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
19
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
20
|
-
DOCUMENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
21
|
-
universalSettings: {
|
|
22
|
-
relationType: RelationType.ONE_TO_MANY,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FieldType,
|
|
3
|
-
OnDeleteAction,
|
|
4
|
-
RelationType,
|
|
5
|
-
defineField,
|
|
6
|
-
} from 'twenty-sdk/define';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
DOCUMENT_FOLDER_CHILD_FOLDERS_UNIVERSAL_IDENTIFIER,
|
|
10
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
DOCUMENT_FOLDER_PARENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
} from 'src/universal-identifiers';
|
|
13
|
-
|
|
14
|
-
export default defineField({
|
|
15
|
-
universalIdentifier: DOCUMENT_FOLDER_PARENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
16
|
-
objectUniversalIdentifier: DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
17
|
-
type: FieldType.RELATION,
|
|
18
|
-
name: 'parentFolder',
|
|
19
|
-
label: 'Родительская папка',
|
|
20
|
-
icon: 'IconFolderUp',
|
|
21
|
-
isNullable: true,
|
|
22
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
23
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
24
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
25
|
-
DOCUMENT_FOLDER_CHILD_FOLDERS_UNIVERSAL_IDENTIFIER,
|
|
26
|
-
universalSettings: {
|
|
27
|
-
relationType: RelationType.MANY_TO_ONE,
|
|
28
|
-
onDelete: OnDeleteAction.SET_NULL,
|
|
29
|
-
joinColumnName: 'parentFolderId',
|
|
30
|
-
},
|
|
31
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FieldType,
|
|
3
|
-
OnDeleteAction,
|
|
4
|
-
RelationType,
|
|
5
|
-
defineField,
|
|
6
|
-
} from 'twenty-sdk/define';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
DOCUMENT_FOLDER_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
10
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
11
|
-
DOCUMENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
12
|
-
DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
13
|
-
} from 'src/universal-identifiers';
|
|
14
|
-
|
|
15
|
-
export default defineField({
|
|
16
|
-
universalIdentifier: DOCUMENT_FOLDER_UNIVERSAL_IDENTIFIER,
|
|
17
|
-
objectUniversalIdentifier: DOCUMENT_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
18
|
-
type: FieldType.RELATION,
|
|
19
|
-
name: 'folder',
|
|
20
|
-
label: 'Папка',
|
|
21
|
-
icon: 'IconFolder',
|
|
22
|
-
isNullable: true,
|
|
23
|
-
relationTargetObjectMetadataUniversalIdentifier:
|
|
24
|
-
DOCUMENT_FOLDER_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
25
|
-
relationTargetFieldMetadataUniversalIdentifier:
|
|
26
|
-
DOCUMENT_FOLDER_DOCUMENTS_UNIVERSAL_IDENTIFIER,
|
|
27
|
-
universalSettings: {
|
|
28
|
-
relationType: RelationType.MANY_TO_ONE,
|
|
29
|
-
onDelete: OnDeleteAction.SET_NULL,
|
|
30
|
-
joinColumnName: 'folderId',
|
|
31
|
-
},
|
|
32
|
-
});
|