@ketvietlab/ketsuite 0.1.22 → 0.1.25
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/dist/cli.js +9 -3
- package/dist/cli.js.map +1 -1
- package/dist/demo/crm.d.ts +3 -0
- package/dist/demo/crm.d.ts.map +1 -0
- package/dist/demo/crm.js +418 -0
- package/dist/demo/crm.js.map +1 -0
- package/dist/demo/partner.d.ts +8 -0
- package/dist/demo/partner.d.ts.map +1 -0
- package/dist/demo/partner.js +179 -0
- package/dist/demo/partner.js.map +1 -0
- package/dist/demo/product.d.ts +25 -0
- package/dist/demo/product.d.ts.map +1 -0
- package/dist/demo/product.js +579 -0
- package/dist/demo/product.js.map +1 -0
- package/dist/demo/purchase.d.ts +4 -0
- package/dist/demo/purchase.d.ts.map +1 -0
- package/dist/demo/purchase.js +58 -0
- package/dist/demo/purchase.js.map +1 -0
- package/dist/demo/sale.d.ts +4 -0
- package/dist/demo/sale.d.ts.map +1 -0
- package/dist/demo/sale.js +52 -0
- package/dist/demo/sale.js.map +1 -0
- package/dist/demo/seed.d.ts +14 -0
- package/dist/demo/seed.d.ts.map +1 -0
- package/dist/demo/seed.js +88 -0
- package/dist/demo/seed.js.map +1 -0
- package/dist/demo/stock.d.ts +7 -0
- package/dist/demo/stock.d.ts.map +1 -0
- package/dist/demo/stock.js +26 -0
- package/dist/demo/stock.js.map +1 -0
- package/dist/demo/user.d.ts +4 -0
- package/dist/demo/user.d.ts.map +1 -0
- package/dist/demo/user.js +41 -0
- package/dist/demo/user.js.map +1 -0
- package/dist/demo/util.d.ts +7 -0
- package/dist/demo/util.d.ts.map +1 -0
- package/dist/demo/util.js +19 -0
- package/dist/demo/util.js.map +1 -0
- package/dist/modules/backend/design/client/backend-shell.d.mts +2 -2
- package/dist/modules/backend/design/client/backend-shell.d.mts.map +1 -1
- package/dist/modules/backend/design/client/backend-shell.mjs +1 -1
- package/dist/modules/backend/design/client/backend-shell.mjs.map +3 -3
- package/dist/modules/backend/design/forms.css +7 -0
- package/dist/modules/backend/screen.d.ts.map +1 -1
- package/dist/modules/backend/screen.js +11 -2
- package/dist/modules/backend/screen.js.map +1 -1
- package/dist/modules/crm/functions/access.d.ts +3 -0
- package/dist/modules/crm/functions/access.d.ts.map +1 -0
- package/dist/modules/crm/functions/access.js +89 -0
- package/dist/modules/crm/functions/access.js.map +1 -0
- package/dist/modules/crm/functions/activities.d.ts +3 -0
- package/dist/modules/crm/functions/activities.d.ts.map +1 -0
- package/dist/modules/crm/functions/activities.js +174 -0
- package/dist/modules/crm/functions/activities.js.map +1 -0
- package/dist/modules/crm/functions/cases.d.ts +3 -0
- package/dist/modules/crm/functions/cases.d.ts.map +1 -0
- package/dist/modules/crm/functions/cases.js +585 -0
- package/dist/modules/crm/functions/cases.js.map +1 -0
- package/dist/modules/crm/functions/configuration.d.ts +3 -0
- package/dist/modules/crm/functions/configuration.d.ts.map +1 -0
- package/dist/modules/crm/functions/configuration.js +331 -0
- package/dist/modules/crm/functions/configuration.js.map +1 -0
- package/dist/modules/crm/functions/gamification.d.ts +3 -0
- package/dist/modules/crm/functions/gamification.d.ts.map +1 -0
- package/dist/modules/crm/functions/gamification.js +58 -0
- package/dist/modules/crm/functions/gamification.js.map +1 -0
- package/dist/modules/crm/functions/index.d.ts +4 -0
- package/dist/modules/crm/functions/index.d.ts.map +1 -0
- package/dist/modules/crm/functions/index.js +33 -0
- package/dist/modules/crm/functions/index.js.map +1 -0
- package/dist/modules/crm/functions/modal-context.d.ts +3 -0
- package/dist/modules/crm/functions/modal-context.d.ts.map +1 -0
- package/dist/modules/crm/functions/modal-context.js +248 -0
- package/dist/modules/crm/functions/modal-context.js.map +1 -0
- package/dist/modules/crm/functions/previews.d.ts +3 -0
- package/dist/modules/crm/functions/previews.d.ts.map +1 -0
- package/dist/modules/crm/functions/previews.js +20 -0
- package/dist/modules/crm/functions/previews.js.map +1 -0
- package/dist/modules/crm/functions/shared.d.ts +31 -0
- package/dist/modules/crm/functions/shared.d.ts.map +1 -0
- package/dist/modules/crm/functions/shared.js +194 -0
- package/dist/modules/crm/functions/shared.js.map +1 -0
- package/dist/modules/crm/index.d.ts +1 -1
- package/dist/modules/crm/index.d.ts.map +1 -1
- package/dist/modules/crm/index.js +2 -2
- package/dist/modules/crm/index.js.map +1 -1
- package/dist/modules/crm/messages.d.ts +4 -1
- package/dist/modules/crm/messages.d.ts.map +1 -1
- package/dist/modules/crm/messages.js +6 -0
- package/dist/modules/crm/messages.js.map +1 -1
- package/dist/modules/crm/record-modal-labels.d.ts +9 -0
- package/dist/modules/crm/record-modal-labels.d.ts.map +1 -0
- package/dist/modules/crm/record-modal-labels.js +36 -0
- package/dist/modules/crm/record-modal-labels.js.map +1 -0
- package/dist/modules/crm/types.d.ts +5 -0
- package/dist/modules/crm/types.d.ts.map +1 -1
- package/dist/modules/crm/types.js +9 -0
- package/dist/modules/crm/types.js.map +1 -1
- package/dist/modules/crm_backend/client/crm-configuration-modal.d.mts +352 -0
- package/dist/modules/crm_backend/client/crm-configuration-modal.d.mts.map +1 -0
- package/dist/modules/crm_backend/client/crm-configuration-modal.mjs +2 -0
- package/dist/modules/crm_backend/client/crm-configuration-modal.mjs.map +7 -0
- package/dist/modules/crm_backend/index.d.ts.map +1 -1
- package/dist/modules/crm_backend/index.js +5 -1
- package/dist/modules/crm_backend/index.js.map +1 -1
- package/dist/modules/crm_backend/islands.d.ts +27 -0
- package/dist/modules/crm_backend/islands.d.ts.map +1 -1
- package/dist/modules/crm_backend/islands.js +22 -0
- package/dist/modules/crm_backend/islands.js.map +1 -1
- package/dist/modules/crm_backend/messages.d.ts +30 -0
- package/dist/modules/crm_backend/messages.d.ts.map +1 -1
- package/dist/modules/crm_backend/messages.js +30 -0
- package/dist/modules/crm_backend/messages.js.map +1 -1
- package/dist/modules/crm_backend/modal/configuration-modal-view.d.ts +55 -0
- package/dist/modules/crm_backend/modal/configuration-modal-view.d.ts.map +1 -0
- package/dist/modules/crm_backend/modal/configuration-modal-view.js +601 -0
- package/dist/modules/crm_backend/modal/configuration-modal-view.js.map +1 -0
- package/dist/modules/crm_backend/routes.d.ts.map +1 -1
- package/dist/modules/crm_backend/routes.js +69 -359
- package/dist/modules/crm_backend/routes.js.map +1 -1
- package/dist/modules/crm_backend/screens/configuration.d.ts +24 -32
- package/dist/modules/crm_backend/screens/configuration.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/configuration.js +183 -274
- package/dist/modules/crm_backend/screens/configuration.js.map +1 -1
- package/dist/modules/crm_backend/screens/index.d.ts +2 -2
- package/dist/modules/crm_backend/screens/index.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/index.js +1 -1
- package/dist/modules/crm_backend/screens/index.js.map +1 -1
- package/dist/modules/product/functions.d.ts +14 -1
- package/dist/modules/product/functions.d.ts.map +1 -1
- package/dist/modules/product/functions.js +36 -31
- package/dist/modules/product/functions.js.map +1 -1
- package/dist/modules/product/product-modal-context.d.ts +3 -0
- package/dist/modules/product/product-modal-context.d.ts.map +1 -0
- package/dist/modules/product/product-modal-context.js +173 -0
- package/dist/modules/product/product-modal-context.js.map +1 -0
- package/dist/modules/product/product-record-tabs.d.ts +14 -0
- package/dist/modules/product/product-record-tabs.d.ts.map +1 -0
- package/dist/modules/product/product-record-tabs.js +23 -0
- package/dist/modules/product/product-record-tabs.js.map +1 -0
- package/dist/modules/product_backend/client/product-modal.d.mts +144 -0
- package/dist/modules/product_backend/client/product-modal.d.mts.map +1 -0
- package/dist/modules/product_backend/client/product-modal.mjs +2 -0
- package/dist/modules/product_backend/client/product-modal.mjs.map +7 -0
- package/dist/modules/product_backend/index.d.ts.map +1 -1
- package/dist/modules/product_backend/index.js +25 -0
- package/dist/modules/product_backend/index.js.map +1 -1
- package/dist/modules/product_backend/islands.d.ts +1 -0
- package/dist/modules/product_backend/islands.d.ts.map +1 -1
- package/dist/modules/product_backend/islands.js +9 -0
- package/dist/modules/product_backend/islands.js.map +1 -1
- package/dist/modules/product_backend/modal/product-modal-view.d.ts +49 -0
- package/dist/modules/product_backend/modal/product-modal-view.d.ts.map +1 -0
- package/dist/modules/product_backend/modal/product-modal-view.js +609 -0
- package/dist/modules/product_backend/modal/product-modal-view.js.map +1 -0
- package/dist/modules/product_backend/routes.d.ts.map +1 -1
- package/dist/modules/product_backend/routes.js +44 -330
- package/dist/modules/product_backend/routes.js.map +1 -1
- package/dist/modules/product_backend/screens/detail.d.ts.map +1 -1
- package/dist/modules/product_backend/screens/detail.js +6 -108
- package/dist/modules/product_backend/screens/detail.js.map +1 -1
- package/dist/modules/product_backend/screens/index.d.ts +0 -1
- package/dist/modules/product_backend/screens/index.d.ts.map +1 -1
- package/dist/modules/product_backend/screens/index.js +0 -1
- package/dist/modules/product_backend/screens/index.js.map +1 -1
- package/dist/modules/product_backend/screens/list.d.ts +3 -1
- package/dist/modules/product_backend/screens/list.d.ts.map +1 -1
- package/dist/modules/product_backend/screens/list.js +6 -5
- package/dist/modules/product_backend/screens/list.js.map +1 -1
- package/dist/modules/user/authorization.d.ts.map +1 -1
- package/dist/modules/user/authorization.js +114 -0
- package/dist/modules/user/authorization.js.map +1 -1
- package/dist/modules/user/functions.d.ts.map +1 -1
- package/dist/modules/user/functions.js +2 -0
- package/dist/modules/user/functions.js.map +1 -1
- package/dist/modules/user/user-modal-context.d.ts +3 -0
- package/dist/modules/user/user-modal-context.d.ts.map +1 -0
- package/dist/modules/user/user-modal-context.js +151 -0
- package/dist/modules/user/user-modal-context.js.map +1 -0
- package/dist/modules/user_backend/client/user-modal.d.mts +72 -0
- package/dist/modules/user_backend/client/user-modal.d.mts.map +1 -0
- package/dist/modules/user_backend/client/user-modal.mjs +2 -0
- package/dist/modules/user_backend/client/user-modal.mjs.map +7 -0
- package/dist/modules/user_backend/index.d.ts.map +1 -1
- package/dist/modules/user_backend/index.js +9 -0
- package/dist/modules/user_backend/index.js.map +1 -1
- package/dist/modules/user_backend/islands.d.ts +15 -0
- package/dist/modules/user_backend/islands.d.ts.map +1 -0
- package/dist/modules/user_backend/islands.js +14 -0
- package/dist/modules/user_backend/islands.js.map +1 -0
- package/dist/modules/user_backend/messages.d.ts +30 -0
- package/dist/modules/user_backend/messages.d.ts.map +1 -1
- package/dist/modules/user_backend/messages.js +30 -0
- package/dist/modules/user_backend/messages.js.map +1 -1
- package/dist/modules/user_backend/modal/user-modal-view.d.ts +26 -0
- package/dist/modules/user_backend/modal/user-modal-view.d.ts.map +1 -0
- package/dist/modules/user_backend/modal/user-modal-view.js +320 -0
- package/dist/modules/user_backend/modal/user-modal-view.js.map +1 -0
- package/dist/modules/user_backend/routes.d.ts.map +1 -1
- package/dist/modules/user_backend/routes.js +15 -3
- package/dist/modules/user_backend/routes.js.map +1 -1
- package/dist/permission-catalogue.d.ts.map +1 -1
- package/dist/permission-catalogue.js +8 -0
- package/dist/permission-catalogue.js.map +1 -1
- package/dist/scaffold/index.js +1 -1
- package/dist/ui/client/record-modal-form.d.ts +67 -0
- package/dist/ui/client/record-modal-form.d.ts.map +1 -0
- package/dist/ui/client/record-modal-form.js +45 -0
- package/dist/ui/client/record-modal-form.js.map +1 -0
- package/dist/ui/client/record-modal.d.ts +103 -6
- package/dist/ui/client/record-modal.d.ts.map +1 -1
- package/dist/ui/client/record-modal.js +333 -65
- package/dist/ui/client/record-modal.js.map +1 -1
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/nav.d.ts +7 -0
- package/dist/ui/nav.d.ts.map +1 -1
- package/dist/ui/nav.js +1 -1
- package/dist/ui/nav.js.map +1 -1
- package/dist/ui/record-modal.d.ts +15 -0
- package/dist/ui/record-modal.d.ts.map +1 -1
- package/dist/ui/record-modal.js +12 -0
- package/dist/ui/record-modal.js.map +1 -1
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/package.json +4 -4
- package/dist/modules/crm/functions.d.ts +0 -10
- package/dist/modules/crm/functions.d.ts.map +0 -1
- package/dist/modules/crm/functions.js +0 -1394
- package/dist/modules/crm/functions.js.map +0 -1
- package/dist/modules/product_backend/screens/create.d.ts +0 -16
- package/dist/modules/product_backend/screens/create.d.ts.map +0 -1
- package/dist/modules/product_backend/screens/create.js +0 -86
- package/dist/modules/product_backend/screens/create.js.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { encodeListState, parseListState, table, text } from '@ketvietlab/ketjs';
|
|
3
|
-
import { formatDateTime, formatMoney, modalWorkspace } from '../../ui/index.js';
|
|
3
|
+
import { formatDateTime, formatMoney, modalWorkspace, recordModalCreateHref, recordModalHref, } from '../../ui/index.js';
|
|
4
4
|
import { formRefusal, readForm, seeOther } from '../backend/forms.js';
|
|
5
|
-
import {
|
|
5
|
+
import { adminPage, inLocale, localeQuery, optional, timezoneOf } from '../backend/screen.js';
|
|
6
6
|
import { withParam } from '../backend/paging.js';
|
|
7
7
|
import { receiveAttachment } from '../storage/routes.js';
|
|
8
8
|
import { caseListSearch } from '../crm/search.js';
|
|
9
|
-
import { caseFormSchema } from '../crm/functions.js';
|
|
9
|
+
import { caseFormSchema } from '../crm/functions/index.js';
|
|
10
10
|
import { assigneeControl, caseControl, partnerControl, productControl, stageControl, tagsControl, teamControl, } from './relation-control.js';
|
|
11
|
-
import {
|
|
11
|
+
import { CONFIGURATION_RECORD_KINDS, CONFIGURATION_SAVE_FUNCTIONS, CONFIGURATION_SECTIONS, CONFIGURATION_STATUSES, caseCloseModal, caseConvertModal, caseCreateScreen, caseDetailScreen, casesListScreen, configurationScreen, leaderboardScreen, plannerScreen, permissionScreen, pipelineScreen, } from './screens/index.js';
|
|
12
12
|
import { keepForListSearch, LIST_PAGE_SIZE, listFacets, listMenus, loadListGroups, } from '../backend/list-search.js';
|
|
13
13
|
const bool = (value) => ['1', 'true', 'on'].includes(value ?? '');
|
|
14
14
|
const errorsOf = (result, _) => (result?.errors ?? []).map((error) => {
|
|
@@ -468,85 +468,57 @@ const pipelineFigures = (_, summary, money) => {
|
|
|
468
468
|
},
|
|
469
469
|
];
|
|
470
470
|
};
|
|
471
|
-
const
|
|
472
|
-
const asked = url.searchParams.get('
|
|
473
|
-
return
|
|
471
|
+
const configurationSectionOf = (url) => {
|
|
472
|
+
const asked = url.searchParams.get('section') ?? '';
|
|
473
|
+
return CONFIGURATION_SECTIONS.includes(asked)
|
|
474
|
+
? asked
|
|
475
|
+
: 'teams';
|
|
474
476
|
};
|
|
475
477
|
const configurationStatusOf = (url) => {
|
|
476
478
|
const asked = url.searchParams.get('status') ?? 'active';
|
|
477
|
-
return
|
|
479
|
+
return CONFIGURATION_STATUSES.includes(asked)
|
|
480
|
+
? asked
|
|
481
|
+
: 'active';
|
|
478
482
|
};
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
return text('not found', { status: 404 });
|
|
519
|
-
const memberEditing = memberAsked && memberAsked !== 'new'
|
|
520
|
-
? (listedMembers.find((row) => String(row.id) === memberAsked) ?? null)
|
|
521
|
-
: null;
|
|
522
|
-
const path = creating
|
|
523
|
-
? '/admin/crm/configuration/teams/new'
|
|
524
|
-
: `/admin/crm/configuration/teams/${encodeURIComponent(requestedId)}`;
|
|
525
|
-
const action = inLocale(url, path);
|
|
526
|
-
const memberAction = memberAsked
|
|
527
|
-
? inLocale(url, `${path}?member=${encodeURIComponent(memberAsked)}`)
|
|
528
|
-
: undefined;
|
|
529
|
-
return adminPage(ctx, url, req, {
|
|
530
|
-
title: 'crm_backend.configuration.title',
|
|
531
|
-
active: '/admin/crm/configuration',
|
|
532
|
-
body: (_, frame) => teamConfigurationScreen(_, frame, {
|
|
533
|
-
team,
|
|
534
|
-
fields: configurationFields(_, 'teams', team, config.teams ?? [], users),
|
|
535
|
-
members: listedMembers,
|
|
536
|
-
action,
|
|
537
|
-
cancelHref: inLocale(url, '/admin/crm/configuration?tab=teams'),
|
|
538
|
-
errors,
|
|
539
|
-
creating,
|
|
540
|
-
memberCreateHref: creating ? undefined : inLocale(url, `${path}?member=new`),
|
|
541
|
-
memberEditHref: creating
|
|
542
|
-
? undefined
|
|
543
|
-
: (row) => inLocale(url, `${path}?member=${encodeURIComponent(String(row.id))}`),
|
|
544
|
-
memberEditing,
|
|
545
|
-
memberCreating: memberAsked === 'new',
|
|
546
|
-
memberFields: memberAsked ? teamMemberFields(_, memberEditing, users) : undefined,
|
|
547
|
-
memberAction,
|
|
548
|
-
}),
|
|
549
|
-
});
|
|
483
|
+
/**
|
|
484
|
+
* Where an old configuration link lives now, or null when it is current.
|
|
485
|
+
*
|
|
486
|
+
* Catalogues used to be `?tab=`, which the record modal reserves for its own tab,
|
|
487
|
+
* and editing used `&edit=<id>` / `&create=1`. A `tab` that names a catalogue and
|
|
488
|
+
* comes without a `record` is the old shape; one next to `record` is a modal tab.
|
|
489
|
+
*/
|
|
490
|
+
const legacyConfigurationHref = (url) => {
|
|
491
|
+
const tab = url.searchParams.get('tab');
|
|
492
|
+
const legacyTab = tab !== null &&
|
|
493
|
+
!url.searchParams.has('record') &&
|
|
494
|
+
CONFIGURATION_SECTIONS.includes(tab);
|
|
495
|
+
const edit = url.searchParams.get('edit');
|
|
496
|
+
const create = url.searchParams.get('create') === '1';
|
|
497
|
+
if (!legacyTab && edit === null && !create)
|
|
498
|
+
return null;
|
|
499
|
+
const section = legacyTab ? tab : configurationSectionOf(url);
|
|
500
|
+
const next = new URL(`${url.pathname}${url.search}`, 'http://ket.local');
|
|
501
|
+
if (legacyTab)
|
|
502
|
+
next.searchParams.delete('tab');
|
|
503
|
+
next.searchParams.delete('edit');
|
|
504
|
+
next.searchParams.delete('create');
|
|
505
|
+
next.searchParams.set('section', section);
|
|
506
|
+
const path = `${next.pathname}${next.search}`;
|
|
507
|
+
const kind = CONFIGURATION_RECORD_KINDS[section];
|
|
508
|
+
if (edit)
|
|
509
|
+
return recordModalHref(path, { kind, id: edit });
|
|
510
|
+
if (create)
|
|
511
|
+
return recordModalCreateHref(path, { kind });
|
|
512
|
+
return path;
|
|
513
|
+
};
|
|
514
|
+
/** The team pages became the team record modal over the teams catalogue. */
|
|
515
|
+
const teamPageRedirect = (creating) => async (url, req, params) => {
|
|
516
|
+
if (req.method !== 'GET')
|
|
517
|
+
return text('GET', { status: 405 });
|
|
518
|
+
const list = inLocale(url, '/admin/crm/configuration?section=teams');
|
|
519
|
+
return seeOther(creating
|
|
520
|
+
? recordModalCreateHref(list, { kind: 'crm.team' })
|
|
521
|
+
: recordModalHref(list, { kind: 'crm.team', id: String(params.id) }));
|
|
550
522
|
};
|
|
551
523
|
export const routes = {
|
|
552
524
|
'/admin/crm': () => async (url, req) => req.method === 'GET' ? seeOther(inLocale(url, '/admin/crm/pipeline')) : text('GET', { status: 405 }),
|
|
@@ -1319,299 +1291,37 @@ export const routes = {
|
|
|
1319
1291
|
const refused = refusePost(req);
|
|
1320
1292
|
if (refused)
|
|
1321
1293
|
return refused;
|
|
1322
|
-
|
|
1323
|
-
|
|
1294
|
+
if (req.method !== 'GET')
|
|
1295
|
+
return text('GET', { status: 405 });
|
|
1296
|
+
const legacy = legacyConfigurationHref(url);
|
|
1297
|
+
if (legacy)
|
|
1298
|
+
return seeOther(legacy);
|
|
1299
|
+
const section = configurationSectionOf(url);
|
|
1324
1300
|
const status = configurationStatusOf(url);
|
|
1325
|
-
const
|
|
1326
|
-
const back = inLocale(url, `/admin/crm/configuration?tab=${tab}${statusQuery}`);
|
|
1327
|
-
if (tab === 'teams' && url.searchParams.has('edit'))
|
|
1328
|
-
return seeOther(inLocale(url, `/admin/crm/configuration/teams/${encodeURIComponent(String(url.searchParams.get('edit')))}`));
|
|
1329
|
-
if (tab === 'teams' && url.searchParams.get('create') === '1')
|
|
1330
|
-
return seeOther(inLocale(url, '/admin/crm/configuration/teams/new'));
|
|
1331
|
-
let errors = [];
|
|
1332
|
-
if (req.method === 'POST') {
|
|
1333
|
-
if (crossSite(req))
|
|
1334
|
-
return text('Forbidden', { status: 403 });
|
|
1335
|
-
const form = await readForm(req);
|
|
1336
|
-
const call = (name, input) => ctx.call(name, input, url, req);
|
|
1337
|
-
const id = form.id || randomUUID();
|
|
1338
|
-
const result = await configurationWrite(call, tab, form, id);
|
|
1339
|
-
if (result.ok)
|
|
1340
|
-
return seeOther(back);
|
|
1341
|
-
errors = errorsOf(result, _);
|
|
1342
|
-
}
|
|
1343
|
-
else if (req.method !== 'GET')
|
|
1344
|
-
return text('GET or POST', { status: 405 });
|
|
1345
|
-
const [config, tags, users] = await Promise.all([
|
|
1301
|
+
const [config, tags, users, canCreate] = await Promise.all([
|
|
1346
1302
|
configuration(ctx, url, req),
|
|
1347
|
-
|
|
1303
|
+
section === 'tags'
|
|
1304
|
+
? allowed(ctx, 'crm.tag.list', { includeArchived: true, limit: 200 }, url, req, [])
|
|
1305
|
+
: Promise.resolve([]),
|
|
1348
1306
|
people(ctx, url, req, 200),
|
|
1307
|
+
ctx.allows(CONFIGURATION_SAVE_FUNCTIONS[section], url, req),
|
|
1349
1308
|
]);
|
|
1350
|
-
const allRows =
|
|
1309
|
+
const allRows = section === 'tags' ? tags : (config[section] ?? []);
|
|
1351
1310
|
const rows = allRows.filter((row) => status === 'all' ? true : status === 'active' ? row.active !== false : row.active === false);
|
|
1352
|
-
const asked = url.searchParams.get('edit');
|
|
1353
|
-
const editing = asked ? (allRows.find((row) => String(row.id) === asked) ?? null) : null;
|
|
1354
|
-
const teams = config.teams ?? [];
|
|
1355
1311
|
return adminPage(ctx, url, req, {
|
|
1356
1312
|
title: 'crm_backend.configuration.title',
|
|
1357
1313
|
body: (_, frame) => configurationScreen(_, frame, {
|
|
1358
|
-
|
|
1314
|
+
section,
|
|
1315
|
+
status,
|
|
1359
1316
|
rows,
|
|
1360
|
-
editing,
|
|
1361
|
-
creating: url.searchParams.get('create') === '1' || (req.method === 'POST' && !editing),
|
|
1362
|
-
errors,
|
|
1363
1317
|
locale: localeQuery(url),
|
|
1364
|
-
|
|
1365
|
-
teams,
|
|
1318
|
+
teams: config.teams ?? [],
|
|
1366
1319
|
users,
|
|
1367
|
-
|
|
1320
|
+
canCreate,
|
|
1368
1321
|
}),
|
|
1369
1322
|
});
|
|
1370
1323
|
},
|
|
1371
|
-
'/admin/crm/configuration/teams/new': (
|
|
1372
|
-
'/admin/crm/configuration/teams/{id}': (
|
|
1324
|
+
'/admin/crm/configuration/teams/new': () => teamPageRedirect(true),
|
|
1325
|
+
'/admin/crm/configuration/teams/{id}': () => teamPageRedirect(false),
|
|
1373
1326
|
};
|
|
1374
|
-
/**
|
|
1375
|
-
* One write per configuration tab.
|
|
1376
|
-
*
|
|
1377
|
-
* The tabs do not share a function signature — a tag saves by name while the
|
|
1378
|
-
* other configuration records save a versioned values bag.
|
|
1379
|
-
*/
|
|
1380
|
-
async function configurationWrite(call, tab, form, id) {
|
|
1381
|
-
const active = bool(form.active);
|
|
1382
|
-
if (tab === 'tags') {
|
|
1383
|
-
return call('crm.tag.save', { id, name: form.name ?? '', active });
|
|
1384
|
-
}
|
|
1385
|
-
const fn = {
|
|
1386
|
-
teams: 'crm.team.save',
|
|
1387
|
-
stages: 'crm.stage.save',
|
|
1388
|
-
assignmentRules: 'crm.assignmentRule.save',
|
|
1389
|
-
scoreRules: 'crm.scoreRule.save',
|
|
1390
|
-
}[tab];
|
|
1391
|
-
const values = {
|
|
1392
|
-
...form,
|
|
1393
|
-
id,
|
|
1394
|
-
active,
|
|
1395
|
-
...(form.expectedVersion ? { expectedVersion: Number(form.expectedVersion) } : {}),
|
|
1396
|
-
...(['stages', 'assignmentRules'].includes(tab)
|
|
1397
|
-
? { allowedKinds: ['lead', 'opportunity'].filter((kind) => bool(form[`kind_${kind}`])) }
|
|
1398
|
-
: {}),
|
|
1399
|
-
...(form.sequence === undefined ? {} : { sequence: Number(form.sequence) }),
|
|
1400
|
-
...(form.priority === undefined ? {} : { priority: Number(form.priority) }),
|
|
1401
|
-
...(form.minimumScore === undefined || form.minimumScore === ''
|
|
1402
|
-
? { minimumScore: null }
|
|
1403
|
-
: { minimumScore: form.minimumScore }),
|
|
1404
|
-
...(form.teamId === '' ? { teamId: null } : {}),
|
|
1405
|
-
...(form.assigneeUserId === '' ? { assigneeUserId: null } : {}),
|
|
1406
|
-
...(form.leaderUserId === '' ? { leaderUserId: null } : {}),
|
|
1407
|
-
...(form.fold === undefined ? {} : { fold: bool(form.fold) }),
|
|
1408
|
-
};
|
|
1409
|
-
delete values.action;
|
|
1410
|
-
delete values.kind_lead;
|
|
1411
|
-
delete values.kind_opportunity;
|
|
1412
|
-
return call(fn, { values, idempotencyKey: randomUUID() });
|
|
1413
|
-
}
|
|
1414
|
-
async function teamMemberWrite(call, form, teamId, id) {
|
|
1415
|
-
return call('crm.team.member.save', {
|
|
1416
|
-
id,
|
|
1417
|
-
teamId,
|
|
1418
|
-
userId: form.userId ?? '',
|
|
1419
|
-
capacity: Number(form.capacity ?? 1),
|
|
1420
|
-
sequence: Number(form.sequence ?? 10),
|
|
1421
|
-
active: bool(form.active),
|
|
1422
|
-
idempotencyKey: randomUUID(),
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
function teamMemberFields(_, editing, users) {
|
|
1426
|
-
const value = (name, fallback = '') => String(editing?.[name] ?? fallback);
|
|
1427
|
-
return [
|
|
1428
|
-
{
|
|
1429
|
-
name: 'userId',
|
|
1430
|
-
label: _('crm_backend.field.assignee'),
|
|
1431
|
-
type: 'select',
|
|
1432
|
-
required: true,
|
|
1433
|
-
value: value('userId'),
|
|
1434
|
-
options: choices(users),
|
|
1435
|
-
},
|
|
1436
|
-
{
|
|
1437
|
-
name: 'capacity',
|
|
1438
|
-
label: _('crm_backend.field.capacity'),
|
|
1439
|
-
type: 'number',
|
|
1440
|
-
value: value('capacity', '1'),
|
|
1441
|
-
help: _('crm_backend.field.capacityHint'),
|
|
1442
|
-
},
|
|
1443
|
-
{
|
|
1444
|
-
name: 'sequence',
|
|
1445
|
-
label: _('crm_backend.field.sequence'),
|
|
1446
|
-
type: 'number',
|
|
1447
|
-
value: value('sequence', '10'),
|
|
1448
|
-
},
|
|
1449
|
-
{
|
|
1450
|
-
name: 'active',
|
|
1451
|
-
label: _('crm_backend.field.active'),
|
|
1452
|
-
type: 'checkbox',
|
|
1453
|
-
value: editing ? editing.active !== false : true,
|
|
1454
|
-
},
|
|
1455
|
-
];
|
|
1456
|
-
}
|
|
1457
|
-
/** The form for one configuration tab, pre-filled when a row is being edited. */
|
|
1458
|
-
function configurationFields(_, tab, editing, teams, users) {
|
|
1459
|
-
const value = (name, fallback = '') => String(editing?.[name] ?? fallback);
|
|
1460
|
-
const common = [
|
|
1461
|
-
{ name: 'name', label: _('crm_backend.field.name'), value: value('name'), required: true },
|
|
1462
|
-
{
|
|
1463
|
-
name: 'active',
|
|
1464
|
-
label: _('crm_backend.field.active'),
|
|
1465
|
-
type: 'checkbox',
|
|
1466
|
-
value: editing ? editing.active !== false : true,
|
|
1467
|
-
},
|
|
1468
|
-
];
|
|
1469
|
-
if (tab === 'tags')
|
|
1470
|
-
return common;
|
|
1471
|
-
if (tab === 'teams')
|
|
1472
|
-
return [
|
|
1473
|
-
...common,
|
|
1474
|
-
{ name: 'code', label: _('crm_backend.field.code'), value: value('code'), required: true },
|
|
1475
|
-
{
|
|
1476
|
-
name: 'leaderUserId',
|
|
1477
|
-
label: _('crm_backend.field.teamLeader'),
|
|
1478
|
-
type: 'select',
|
|
1479
|
-
value: value('leaderUserId'),
|
|
1480
|
-
options: [{ value: '', label: _('crm_backend.value.unset') }, ...choices(users)],
|
|
1481
|
-
},
|
|
1482
|
-
{
|
|
1483
|
-
name: 'assignmentMode',
|
|
1484
|
-
label: _('crm_backend.field.assignmentMode'),
|
|
1485
|
-
type: 'select',
|
|
1486
|
-
value: value('assignmentMode', 'manual'),
|
|
1487
|
-
options: ['manual', 'round_robin', 'capacity'].map((item) => ({
|
|
1488
|
-
value: item,
|
|
1489
|
-
label: _(`crm_backend.assignmentMode.${item}`),
|
|
1490
|
-
})),
|
|
1491
|
-
},
|
|
1492
|
-
];
|
|
1493
|
-
if (tab === 'stages')
|
|
1494
|
-
return [
|
|
1495
|
-
...common,
|
|
1496
|
-
{ name: 'code', label: _('crm_backend.field.code'), value: value('code'), required: true },
|
|
1497
|
-
{
|
|
1498
|
-
name: 'sequence',
|
|
1499
|
-
label: _('crm_backend.field.sequence'),
|
|
1500
|
-
type: 'number',
|
|
1501
|
-
value: value('sequence', '10'),
|
|
1502
|
-
},
|
|
1503
|
-
{
|
|
1504
|
-
name: 'allowedKinds',
|
|
1505
|
-
label: _('crm_backend.field.allowedKinds'),
|
|
1506
|
-
type: 'checkbox-group',
|
|
1507
|
-
required: true,
|
|
1508
|
-
options: ['lead', 'opportunity'].map((kind) => ({
|
|
1509
|
-
name: `kind_${kind}`,
|
|
1510
|
-
value: '1',
|
|
1511
|
-
label: _(`crm.kind.${kind}`),
|
|
1512
|
-
checked: editing
|
|
1513
|
-
? Array.isArray(editing.allowedKinds) && editing.allowedKinds.includes(kind)
|
|
1514
|
-
: true,
|
|
1515
|
-
})),
|
|
1516
|
-
},
|
|
1517
|
-
{
|
|
1518
|
-
name: 'teamId',
|
|
1519
|
-
label: _('crm_backend.field.team'),
|
|
1520
|
-
type: 'select',
|
|
1521
|
-
value: value('teamId'),
|
|
1522
|
-
options: [{ value: '', label: _('crm_backend.value.allTeams') }, ...choices(teams)],
|
|
1523
|
-
},
|
|
1524
|
-
{
|
|
1525
|
-
name: 'terminalState',
|
|
1526
|
-
label: _('crm_backend.field.state'),
|
|
1527
|
-
type: 'select',
|
|
1528
|
-
value: value('terminalState', 'open'),
|
|
1529
|
-
options: ['open', 'won', 'lost'].map((item) => ({ value: item, label: _(`crm.terminal.${item}`) })),
|
|
1530
|
-
},
|
|
1531
|
-
{
|
|
1532
|
-
name: 'fold',
|
|
1533
|
-
label: _('crm_backend.field.fold'),
|
|
1534
|
-
type: 'checkbox',
|
|
1535
|
-
value: editing?.fold === true,
|
|
1536
|
-
},
|
|
1537
|
-
];
|
|
1538
|
-
if (tab === 'assignmentRules')
|
|
1539
|
-
return [
|
|
1540
|
-
...common,
|
|
1541
|
-
{
|
|
1542
|
-
name: 'priority',
|
|
1543
|
-
label: _('crm_backend.field.priority'),
|
|
1544
|
-
type: 'number',
|
|
1545
|
-
value: value('priority', '10'),
|
|
1546
|
-
},
|
|
1547
|
-
{
|
|
1548
|
-
name: 'allowedKinds',
|
|
1549
|
-
label: _('crm_backend.field.allowedKinds'),
|
|
1550
|
-
type: 'checkbox-group',
|
|
1551
|
-
required: true,
|
|
1552
|
-
options: ['lead', 'opportunity'].map((kind) => ({
|
|
1553
|
-
name: `kind_${kind}`,
|
|
1554
|
-
value: '1',
|
|
1555
|
-
label: _(`crm.kind.${kind}`),
|
|
1556
|
-
checked: editing
|
|
1557
|
-
? Array.isArray(editing.allowedKinds) && editing.allowedKinds.includes(kind)
|
|
1558
|
-
: true,
|
|
1559
|
-
})),
|
|
1560
|
-
},
|
|
1561
|
-
{
|
|
1562
|
-
name: 'teamId',
|
|
1563
|
-
label: _('crm_backend.field.team'),
|
|
1564
|
-
type: 'select',
|
|
1565
|
-
required: true,
|
|
1566
|
-
value: value('teamId'),
|
|
1567
|
-
options: choices(teams),
|
|
1568
|
-
},
|
|
1569
|
-
{
|
|
1570
|
-
name: 'assigneeUserId',
|
|
1571
|
-
label: _('crm_backend.field.assignee'),
|
|
1572
|
-
type: 'select',
|
|
1573
|
-
value: value('assigneeUserId'),
|
|
1574
|
-
options: [{ value: '', label: _('crm_backend.value.teamMode') }, ...choices(users)],
|
|
1575
|
-
},
|
|
1576
|
-
{ name: 'utmSource', label: _('crm_backend.field.utmSource'), value: value('utmSource') },
|
|
1577
|
-
{
|
|
1578
|
-
name: 'minimumScore',
|
|
1579
|
-
label: _('crm_backend.field.minimumScore'),
|
|
1580
|
-
type: 'number',
|
|
1581
|
-
value: value('minimumScore'),
|
|
1582
|
-
},
|
|
1583
|
-
];
|
|
1584
|
-
return [
|
|
1585
|
-
...common,
|
|
1586
|
-
{
|
|
1587
|
-
name: 'field',
|
|
1588
|
-
label: _('crm_backend.field.ruleField'),
|
|
1589
|
-
type: 'select',
|
|
1590
|
-
value: value('field', 'email'),
|
|
1591
|
-
required: true,
|
|
1592
|
-
options: ['email', 'utmSource', 'expectedRevenue'].map((field) => ({
|
|
1593
|
-
value: field,
|
|
1594
|
-
label: _(`crm_backend.scoreField.${field}`),
|
|
1595
|
-
})),
|
|
1596
|
-
},
|
|
1597
|
-
{
|
|
1598
|
-
name: 'operator',
|
|
1599
|
-
label: _('crm_backend.field.operator'),
|
|
1600
|
-
type: 'select',
|
|
1601
|
-
value: value('operator', 'eq'),
|
|
1602
|
-
options: ['eq', 'contains', 'present', 'gte'].map((item) => ({
|
|
1603
|
-
value: item,
|
|
1604
|
-
label: _(`crm_backend.operator.${item}`),
|
|
1605
|
-
})),
|
|
1606
|
-
},
|
|
1607
|
-
{ name: 'value', label: _('crm_backend.field.ruleValue'), value: value('value') },
|
|
1608
|
-
{ name: 'points', label: _('crm_backend.field.points'), type: 'number', value: value('points', '0') },
|
|
1609
|
-
{
|
|
1610
|
-
name: 'sequence',
|
|
1611
|
-
label: _('crm_backend.field.sequence'),
|
|
1612
|
-
type: 'number',
|
|
1613
|
-
value: value('sequence', '10'),
|
|
1614
|
-
},
|
|
1615
|
-
];
|
|
1616
|
-
}
|
|
1617
1327
|
//# sourceMappingURL=routes.js.map
|