@cratis/scene.blueprint.approvals 0.0.0-stage → 4.53.1

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.
Files changed (130) hide show
  1. package/README.md +66 -2
  2. package/approvalsApplication.ts +28 -0
  3. package/approvalsParts.ts +50 -0
  4. package/approvalsQueries.ts +58 -0
  5. package/approvalsScreenSet.ts +24 -0
  6. package/blueprint.ts +16 -0
  7. package/blueprintCatalog.json +171 -0
  8. package/dist/cjs/approvalsApplication.js +49 -0
  9. package/dist/cjs/approvalsApplication.js.map +1 -0
  10. package/dist/cjs/approvalsParts.js +131 -0
  11. package/dist/cjs/approvalsParts.js.map +1 -0
  12. package/dist/cjs/approvalsQueries.js +68 -0
  13. package/dist/cjs/approvalsQueries.js.map +1 -0
  14. package/dist/cjs/approvalsScreenSet.js +61 -0
  15. package/dist/cjs/approvalsScreenSet.js.map +1 -0
  16. package/dist/cjs/blueprint.js +19 -0
  17. package/dist/cjs/blueprint.js.map +1 -0
  18. package/dist/cjs/index.js +67 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/manifest.js +71 -0
  21. package/dist/cjs/manifest.js.map +1 -0
  22. package/dist/cjs/navigation.js +117 -0
  23. package/dist/cjs/navigation.js.map +1 -0
  24. package/dist/cjs/package.json +3 -0
  25. package/dist/cjs/packageName.js +8 -0
  26. package/dist/cjs/packageName.js.map +1 -0
  27. package/dist/cjs/screens/index.js +23 -0
  28. package/dist/cjs/screens/index.js.map +1 -0
  29. package/dist/cjs/templateProvenance.js +24 -0
  30. package/dist/cjs/templateProvenance.js.map +1 -0
  31. package/dist/cjs/templates/formTemplates.js +111 -0
  32. package/dist/cjs/templates/formTemplates.js.map +1 -0
  33. package/dist/cjs/templates/index.js +31 -0
  34. package/dist/cjs/templates/index.js.map +1 -0
  35. package/dist/cjs/templates/listTemplates.js +221 -0
  36. package/dist/cjs/templates/listTemplates.js.map +1 -0
  37. package/dist/cjs/templates/recordTemplates.js +97 -0
  38. package/dist/cjs/templates/recordTemplates.js.map +1 -0
  39. package/dist/cjs/templates/wizardTemplate.js +77 -0
  40. package/dist/cjs/templates/wizardTemplate.js.map +1 -0
  41. package/dist/esm/approvalsApplication.d.ts +10 -0
  42. package/dist/esm/approvalsApplication.d.ts.map +1 -0
  43. package/dist/esm/approvalsApplication.js +44 -0
  44. package/dist/esm/approvalsApplication.js.map +1 -0
  45. package/dist/esm/approvalsParts.d.ts +13 -0
  46. package/dist/esm/approvalsParts.d.ts.map +1 -0
  47. package/dist/esm/approvalsParts.js +114 -0
  48. package/dist/esm/approvalsParts.js.map +1 -0
  49. package/dist/esm/approvalsQueries.d.ts +51 -0
  50. package/dist/esm/approvalsQueries.d.ts.map +1 -0
  51. package/dist/esm/approvalsQueries.js +63 -0
  52. package/dist/esm/approvalsQueries.js.map +1 -0
  53. package/dist/esm/approvalsScreenSet.d.ts +7 -0
  54. package/dist/esm/approvalsScreenSet.d.ts.map +1 -0
  55. package/dist/esm/approvalsScreenSet.js +59 -0
  56. package/dist/esm/approvalsScreenSet.js.map +1 -0
  57. package/dist/esm/blueprint.d.ts +3 -0
  58. package/dist/esm/blueprint.d.ts.map +1 -0
  59. package/dist/esm/blueprint.js +17 -0
  60. package/dist/esm/blueprint.js.map +1 -0
  61. package/dist/esm/index.d.ts +12 -0
  62. package/dist/esm/index.d.ts.map +1 -0
  63. package/dist/esm/index.js +17 -0
  64. package/dist/esm/index.js.map +1 -0
  65. package/dist/esm/manifest.d.ts +3 -0
  66. package/dist/esm/manifest.d.ts.map +1 -0
  67. package/dist/esm/manifest.js +69 -0
  68. package/dist/esm/manifest.js.map +1 -0
  69. package/dist/esm/navigation.d.ts +5 -0
  70. package/dist/esm/navigation.d.ts.map +1 -0
  71. package/dist/esm/navigation.js +113 -0
  72. package/dist/esm/navigation.js.map +1 -0
  73. package/dist/esm/package.json +3 -0
  74. package/dist/esm/packageName.d.ts +2 -0
  75. package/dist/esm/packageName.d.ts.map +1 -0
  76. package/dist/esm/packageName.js +6 -0
  77. package/dist/esm/packageName.js.map +1 -0
  78. package/dist/esm/screens/index.d.ts +3 -0
  79. package/dist/esm/screens/index.d.ts.map +1 -0
  80. package/dist/esm/screens/index.js +21 -0
  81. package/dist/esm/screens/index.js.map +1 -0
  82. package/dist/esm/templateProvenance.d.ts +3 -0
  83. package/dist/esm/templateProvenance.d.ts.map +1 -0
  84. package/dist/esm/templateProvenance.js +22 -0
  85. package/dist/esm/templateProvenance.js.map +1 -0
  86. package/dist/esm/templates/formTemplates.d.ts +6 -0
  87. package/dist/esm/templates/formTemplates.d.ts.map +1 -0
  88. package/dist/esm/templates/formTemplates.js +106 -0
  89. package/dist/esm/templates/formTemplates.js.map +1 -0
  90. package/dist/esm/templates/index.d.ts +7 -0
  91. package/dist/esm/templates/index.d.ts.map +1 -0
  92. package/dist/esm/templates/index.js +20 -0
  93. package/dist/esm/templates/index.js.map +1 -0
  94. package/dist/esm/templates/listTemplates.d.ts +6 -0
  95. package/dist/esm/templates/listTemplates.d.ts.map +1 -0
  96. package/dist/esm/templates/listTemplates.js +216 -0
  97. package/dist/esm/templates/listTemplates.js.map +1 -0
  98. package/dist/esm/templates/recordTemplates.d.ts +3 -0
  99. package/dist/esm/templates/recordTemplates.d.ts.map +1 -0
  100. package/dist/esm/templates/recordTemplates.js +95 -0
  101. package/dist/esm/templates/recordTemplates.js.map +1 -0
  102. package/dist/esm/templates/wizardTemplate.d.ts +3 -0
  103. package/dist/esm/templates/wizardTemplate.d.ts.map +1 -0
  104. package/dist/esm/templates/wizardTemplate.js +75 -0
  105. package/dist/esm/templates/wizardTemplate.js.map +1 -0
  106. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  107. package/index.ts +14 -0
  108. package/manifest.ts +44 -0
  109. package/navigation.ts +54 -0
  110. package/package.json +78 -4
  111. package/packageName.ts +5 -0
  112. package/sampleData/approvals-general.json +1269 -0
  113. package/sampleData/approvals-nordic.json +1269 -0
  114. package/screens/index.ts +21 -0
  115. package/templateProvenance.ts +15 -0
  116. package/templates/formTemplates.ts +61 -0
  117. package/templates/index.ts +19 -0
  118. package/templates/listTemplates.ts +116 -0
  119. package/templates/recordTemplates.ts +45 -0
  120. package/templates/wizardTemplate.ts +33 -0
  121. package/thumbnails/AllRequests.svg +13 -0
  122. package/thumbnails/ApprovalInbox.svg +23 -0
  123. package/thumbnails/DecisionDialog.svg +11 -0
  124. package/thumbnails/MyRequests.svg +13 -0
  125. package/thumbnails/NewRequestWizard.svg +14 -0
  126. package/thumbnails/RequestPage.svg +11 -0
  127. package/thumbnails/RequestTypeEditForm.svg +14 -0
  128. package/thumbnails/RequestTypeQuickCreate.svg +11 -0
  129. package/thumbnails/RequestTypes.svg +13 -0
  130. package/thumbnails/approvals.svg +9 -0
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { Screen } from '@cratis/scene.model';
5
+ import { LayoutName } from '@cratis/scene.blueprint.default';
6
+ import { approvalsScreenDefinitions } from '../approvalsScreenSet';
7
+
8
+ /**
9
+ * The ready-to-use screens: real `Screen` instances, one for each entry of the manifest's `blueprint.screenSet`, each filling the screen template it names in the
10
+ * foundation's application shell. A new application that adopts the blueprint gets these, wired into
11
+ * its navigation (`approvalsNavigation`).
12
+ */
13
+ export const approvalsScreens: Screen[] = approvalsScreenDefinitions.map(definition => ({
14
+ name: definition.name,
15
+ layout: LayoutName.AppShell,
16
+ screenTemplate: definition.template,
17
+ slotContent: {},
18
+ forms: [],
19
+ contributions: [],
20
+ path: definition.name.split('.'),
21
+ }));
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { TemplateMetadata } from '@cratis/scene.model';
5
+
6
+ /** The compatibility, attribution and license metadata every template this blueprint ships carries. */
7
+ export const approvalsTemplateProvenance: Pick<TemplateMetadata, 'compatibility' | 'attribution' | 'license' | 'licenseUrl'> = {
8
+ compatibility: {
9
+ scene: '^4.13.0',
10
+ packages: [{ name: 'Cratis.Blueprint.Default', versionRange: '^1.0.0' }],
11
+ },
12
+ attribution: { author: 'Cratis', url: 'https://github.com/Cratis/Scene/tree/main/Source/JavaScript/blueprint.approvals' },
13
+ license: 'MIT',
14
+ licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE',
15
+ };
@@ -0,0 +1,61 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { DialogTemplate, ScreenTemplate, TemplateScope } from '@cratis/scene.model';
5
+ import { formScreenTemplate, quickCreateDialogTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ApprovalsQuery, fromQuery, localeOfData } from '../approvalsQueries';
7
+ import { approvalsMetadata, closesDialog, component, withBehaviors } from '../approvalsParts';
8
+
9
+ /** The request type editor: what a type asks for, how many steps approve it and who decides each. For administrators. */
10
+ export const requestTypeEditFormTemplate: ScreenTemplate = {
11
+ name: 'RequestTypeEditForm',
12
+ fitsSlot: 'content',
13
+ slots: formScreenTemplate.slots,
14
+ arrangement: formScreenTemplate.arrangement,
15
+ content: {
16
+ header: [component('request-type-header', 'pageHeader', { title: 'Edit request type', subtitle: 'What it asks for and who approves it' })],
17
+ body: [component('request-type-body', 'formScreenBody', { mode: 'edit', sections: fromQuery(ApprovalsQuery.TypeEditorSections), errors: fromQuery(ApprovalsQuery.FormErrors, '0'), ...localeOfData })],
18
+ actions: [],
19
+ },
20
+ displayName: 'Edit request type',
21
+ description: 'A form that edits a request type: its name, what it asks for and its approval steps.',
22
+ metadata: approvalsMetadata('RequestTypeEditForm', 'Form', [TemplateScope.Feature, TemplateScope.Subfeature]),
23
+ };
24
+
25
+ /**
26
+ * The decision dialog (the foundation confirm dialog with a comment field): says which decision is being made - approve, reject or request changes -
27
+ * and asks for a comment that the requester will see. The commit verb is the decision's.
28
+ */
29
+ export const decisionDialogTemplate: DialogTemplate = {
30
+ name: 'DecisionDialog',
31
+ slots: quickCreateDialogTemplate.slots,
32
+ content: {
33
+ header: [component('decision-frame', 'dialogFrame', { title: 'Your decision', subtitle: 'Say why - the requester will see it' })],
34
+ body: [withBehaviors(component('decision-form', 'formScreenBody', {
35
+ mode: 'create', saveAndNew: false, strings: { formSave: 'Decide' }, sections: fromQuery(ApprovalsQuery.DecisionSections), errors: fromQuery(ApprovalsQuery.FormErrors, '0'), ...localeOfData,
36
+ }), closesDialog())],
37
+ actions: [],
38
+ },
39
+ displayName: 'Decision',
40
+ description: 'A confirmation with a decision (approve, reject or request changes) and a comment for the requester.',
41
+ metadata: approvalsMetadata('DecisionDialog', 'Dialog', [TemplateScope.Slice]),
42
+ };
43
+
44
+ /** A short form that adds a request type to the list without leaving it. */
45
+ export const requestTypeQuickCreateDialogTemplate: DialogTemplate = {
46
+ name: 'RequestTypeQuickCreate',
47
+ slots: quickCreateDialogTemplate.slots,
48
+ content: {
49
+ header: [component('request-type-frame', 'dialogFrame', { title: 'New request type', subtitle: 'Only what is needed to get started' })],
50
+ body: [withBehaviors(component('request-type-quick', 'formScreenBody', {
51
+ mode: 'create', saveAndNew: false, strings: { formSave: 'Create' }, sections: fromQuery(ApprovalsQuery.TypeEditorSections), errors: fromQuery(ApprovalsQuery.FormErrors, '0'), ...localeOfData,
52
+ }), closesDialog())],
53
+ actions: [],
54
+ },
55
+ displayName: 'New request type',
56
+ description: 'A short form that adds a request type without leaving the page.',
57
+ metadata: approvalsMetadata('RequestTypeQuickCreate', 'Dialog', [TemplateScope.Slice]),
58
+ };
59
+
60
+ /** The dialogs of the approvals application. */
61
+ export const approvalsDialogTemplates: DialogTemplate[] = [decisionDialogTemplate, requestTypeQuickCreateDialogTemplate];
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { requestTypeEditFormTemplate } from './formTemplates';
5
+ import { allRequestsTemplate, approvalInboxTemplate, myRequestsTemplate, requestTypesTemplate } from './listTemplates';
6
+ import { requestPageTemplate } from './recordTemplates';
7
+ import { newRequestWizardTemplate } from './wizardTemplate';
8
+
9
+ export * from './listTemplates';
10
+ export * from './wizardTemplate';
11
+ export * from './recordTemplates';
12
+ export * from './formTemplates';
13
+
14
+ /** Every screen template this blueprint provides, in the order the manifest lists them. */
15
+ export const approvalsScreenTemplates = [
16
+ approvalInboxTemplate, myRequestsTemplate, newRequestWizardTemplate, requestPageTemplate, allRequestsTemplate, requestTypesTemplate, requestTypeEditFormTemplate,
17
+ ];
18
+
19
+ export { approvalsDialogTemplates } from './formTemplates';
@@ -0,0 +1,116 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { InteractionActionKind, InteractionTriggerKind, NotificationLevel, NotifyAction, ScreenTemplate, TemplateScope } from '@cratis/scene.model';
5
+ import { listScreenTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ApprovalsQuery, fromQuery, localeOfData } from '../approvalsQueries';
7
+ import { actionButton, approvalsMetadata, component, goesTo, opensDialog, opensRecordOnSelect, withBehaviors } from '../approvalsParts';
8
+
9
+ const listScopes = [TemplateScope.Module, TemplateScope.Feature];
10
+
11
+ /** The Export button: it tells the user the export has started, which is what the shell does for a long-running action it does not wait on. */
12
+ const exportAction = (id: string) => withBehaviors(actionButton(id, 'Export', 'secondary'), [{
13
+ bindings: [{
14
+ trigger: { kind: InteractionTriggerKind.Click },
15
+ actions: [{ kind: InteractionActionKind.Notify, level: NotificationLevel.Info, message: { text: 'The export has started.' } } as unknown as NotifyAction],
16
+ }],
17
+ }]);
18
+
19
+ interface ListOptions {
20
+ name: string;
21
+ displayName: string;
22
+ description: string;
23
+ title: string;
24
+ subtitle: string;
25
+ searchLabel: string;
26
+ urlKey: string;
27
+ rows: string;
28
+ columns: string;
29
+ filterFields: string;
30
+ views: string;
31
+ columnChoices?: string;
32
+ selection?: string;
33
+ rowActions: string[];
34
+ bulkActions?: string[];
35
+ recordScreen?: string;
36
+
37
+ /** The primary button of the header: its label and what it does. */
38
+ primary?: { label: string; behaviors: ReturnType<typeof goesTo> };
39
+
40
+ /** Draw the rows as cards with their actions as buttons, as an approver decides. */
41
+ decide?: boolean;
42
+ }
43
+
44
+ /**
45
+ * One approvals list: the foundation `ListScreen` with its header, toolbar, filters, list and bulk bar filled. The slots, arrangement and every behavior -
46
+ * sort, search, paging and selection in the address, the table collapsing to cards on a phone - are the foundation's.
47
+ */
48
+ function listTemplateOf(options: ListOptions): ScreenTemplate {
49
+ const id = options.name;
50
+ const listId = `${id}-records`;
51
+ const list = component(listId, 'dataList', {
52
+ label: options.title, rows: fromQuery(options.rows), columns: fromQuery(options.columns), titleField: 'title', pageSize: options.decide ? 6 : 10, rowActions: options.rowActions, urlKey: options.urlKey,
53
+ ...(options.decide ? { variant: 'cards', rowActionStyle: 'buttons', toneField: 'tone' } : {}),
54
+ selectionMode: options.recordScreen || options.decide ? 'single' : 'multiple', ...localeOfData,
55
+ });
56
+ const toolbar = [
57
+ component(`${id}-search`, 'globalSearch', { placeholder: options.searchLabel, label: options.searchLabel, urlKey: `${options.urlKey}q` }),
58
+ component(`${id}-views`, 'savedViewsMenu', { views: fromQuery(options.views), savePermission: 'enabled', managePermission: 'enabled' }),
59
+ ...(options.columnChoices ? [component(`${id}-columns`, 'columnChooser', { columns: fromQuery(options.columnChoices) })] : []),
60
+ ];
61
+
62
+ return {
63
+ name: options.name,
64
+ fitsSlot: 'content',
65
+ slots: listScreenTemplate.slots,
66
+ arrangement: listScreenTemplate.arrangement,
67
+ content: {
68
+ header: [component(`${id}-header`, 'pageHeader', { title: options.title, subtitle: options.subtitle }, {
69
+ actions: [exportAction(`${id}-export`), ...(options.primary ? [withBehaviors(actionButton(`${id}-primary`, options.primary.label, 'primary'), options.primary.behaviors)] : [])],
70
+ })],
71
+ toolbar,
72
+ filters: [component(`${id}-filter`, 'filterBuilder', { fields: fromQuery(options.filterFields), ...localeOfData })],
73
+ list: [options.recordScreen ? withBehaviors(list, opensRecordOnSelect(listId, options.recordScreen)) : options.decide ? withBehaviors(list, opensDialog('DecisionDialog')) : list],
74
+ bulkBar: options.bulkActions && options.selection && !options.recordScreen && !options.decide ? [component(`${id}-bulk`, 'bulkBar', { selection: fromQuery(options.selection), actions: options.bulkActions })] : [],
75
+ footer: [],
76
+ },
77
+ displayName: options.displayName,
78
+ description: options.description,
79
+ metadata: approvalsMetadata(options.name, 'List', listScopes),
80
+ };
81
+ }
82
+
83
+ /**
84
+ * The approval inbox: the requests waiting for the signed-in person as cards (the foundation list's Cards variant), each with its type, who asked, the amount or
85
+ * dates, how long it has waited and **Approve, Reject and Request changes as buttons on the card**. Pressing one opens the decision dialog for that decision,
86
+ * so a decision always carries a comment. A card's tone says how overdue it is, and the words say the same.
87
+ */
88
+ export const approvalInboxTemplate = listTemplateOf({
89
+ name: 'ApprovalInbox', displayName: 'Approval inbox', description: 'The requests waiting for my decision as cards, with Approve, Reject and Request changes inline.',
90
+ title: 'Inbox', subtitle: 'Waiting for your decision', searchLabel: 'Search the inbox', urlKey: 'inbox', rows: ApprovalsQuery.Inbox, columns: ApprovalsQuery.InboxColumns,
91
+ filterFields: ApprovalsQuery.InboxFilterFields, views: ApprovalsQuery.InboxViews, rowActions: ['Approve', 'Reject', 'Request changes'], decide: true,
92
+ });
93
+
94
+ /** The requests I made: draft, submitted, approved and rejected as chips, and a New request button that starts the wizard. Choosing a request opens it. */
95
+ export const myRequestsTemplate = listTemplateOf({
96
+ name: 'MyRequests', displayName: 'My requests', description: 'The requests I made, with draft, submitted, approved and rejected as chips.',
97
+ title: 'My requests', subtitle: 'What I asked for and where it stands', searchLabel: 'Search my requests', urlKey: 'requests',
98
+ rows: ApprovalsQuery.MyRequests, columns: ApprovalsQuery.MyRequestColumns, filterFields: ApprovalsQuery.MyRequestFilterFields, views: ApprovalsQuery.MyRequestViews, columnChoices: ApprovalsQuery.MyRequestColumnChoices,
99
+ selection: ApprovalsQuery.MyRequestSelection, rowActions: ['Withdraw', 'Delete draft'], bulkActions: ['Withdraw'], recordScreen: 'approvals.requests.page', primary: { label: 'New request', behaviors: goesTo('approvals.requests.new') },
100
+ });
101
+
102
+ /** Every request of the organisation, with who asked, who decides and where each stands. */
103
+ export const allRequestsTemplate = listTemplateOf({
104
+ name: 'AllRequests', displayName: 'All requests', description: 'Every request of the organisation with its type, requester, current approver and status.',
105
+ title: 'All requests', subtitle: 'Every request in the organisation', searchLabel: 'Search all requests', urlKey: 'all',
106
+ rows: ApprovalsQuery.AllRequests, columns: ApprovalsQuery.AllRequestColumns, filterFields: ApprovalsQuery.AllRequestFilterFields, views: ApprovalsQuery.AllRequestViews, columnChoices: ApprovalsQuery.AllRequestColumnChoices,
107
+ selection: ApprovalsQuery.AllRequestSelection, rowActions: ['Reassign', 'Cancel'], bulkActions: ['Reassign', 'Cancel'], recordScreen: 'approvals.requests.page',
108
+ });
109
+
110
+ /** The request types an organisation offers: what each asks for, how many steps approve it and whether it is active. For administrators. Choosing one edits it. */
111
+ export const requestTypesTemplate = listTemplateOf({
112
+ name: 'RequestTypes', displayName: 'Request types', description: 'The request types an organisation offers, with the steps that approve each and whether it is active.',
113
+ title: 'Templates', subtitle: 'The request types people can choose from', searchLabel: 'Search request types', urlKey: 'types',
114
+ rows: ApprovalsQuery.RequestTypes, columns: ApprovalsQuery.RequestTypeColumns, filterFields: ApprovalsQuery.RequestTypeFilterFields, views: ApprovalsQuery.RequestTypeViews, columnChoices: ApprovalsQuery.RequestTypeColumnChoices,
115
+ selection: ApprovalsQuery.RequestTypeSelection, rowActions: ['Duplicate', 'Deactivate'], bulkActions: ['Deactivate'], recordScreen: 'approvals.templates.edit', primary: { label: 'New request type', behaviors: opensDialog('RequestTypeQuickCreate') },
116
+ });
@@ -0,0 +1,45 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ScreenTemplate, TemplateScope } from '@cratis/scene.model';
5
+ import { recordPageTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ApprovalsQuery, currencyOfData, fromQuery, localeOfData } from '../approvalsQueries';
7
+ import { actionButton, approvalsMetadata, component, opensDialog, withBehaviors } from '../approvalsParts';
8
+
9
+ /**
10
+ * The request page: the foundation `RecordPage` with the request's title, its key facts under it - status, who asked, the amount - and the **approval chain**
11
+ * as the page's first block: the steps in order, who decides each and where it stands. A rejection stops the chain and the steps after it read "Not reached"; the
12
+ * outcome is said in words above the steps. The request's fields, its **attachments** and its **comments** (the page's activity) follow, and the decision
13
+ * buttons open the decision dialog.
14
+ */
15
+ export const requestPageTemplate: ScreenTemplate = {
16
+ name: 'RequestPage',
17
+ fitsSlot: 'content',
18
+ slots: recordPageTemplate.slots,
19
+ arrangement: recordPageTemplate.arrangement,
20
+ content: {
21
+ header: [component('request-header', 'pageHeader', { title: fromQuery(ApprovalsQuery.Request, '0.title'), subtitle: fromQuery(ApprovalsQuery.Request, '0.reference') }, {
22
+ actions: [
23
+ withBehaviors(actionButton('request-approve', 'Approve', 'primary'), opensDialog('DecisionDialog')),
24
+ withBehaviors(actionButton('request-reject', 'Reject', 'secondary'), opensDialog('DecisionDialog')),
25
+ withBehaviors(actionButton('request-changes', 'Request changes', 'secondary'), opensDialog('DecisionDialog')),
26
+ ],
27
+ })],
28
+ summary: [
29
+ component('request-status', 'statusChip', { status: fromQuery(ApprovalsQuery.RequestSummary, '0.status'), tone: fromQuery(ApprovalsQuery.RequestSummary, '0.tone') }),
30
+ component('request-amount', 'statCard', { label: fromQuery(ApprovalsQuery.RequestSummary, '0.amountLabel'), value: fromQuery(ApprovalsQuery.RequestSummary, '0.amount'), format: 'currency', fractionDigits: 0, ...currencyOfData }),
31
+ component('request-people', 'avatarStack', { people: fromQuery(ApprovalsQuery.RequestSummary, '0.people') }),
32
+ ],
33
+ tabs: [component('request-tabs', 'tabSet', { tabs: fromQuery(ApprovalsQuery.RequestTabs), urlKey: 'tab', label: 'Request sections' })],
34
+ main: [
35
+ component('request-chain', 'approvalChainStepper', { steps: fromQuery(ApprovalsQuery.Chain), label: 'Approval chain', ...localeOfData }),
36
+ component('request-form', 'formScreenBody', { mode: 'readOnly', sections: fromQuery(ApprovalsQuery.RequestSections), values: fromQuery(ApprovalsQuery.Request, '0'), ...localeOfData }),
37
+ ],
38
+ related: [component('request-attachments', 'dataList', { label: 'Attachments', rows: fromQuery(ApprovalsQuery.Attachments), columns: fromQuery(ApprovalsQuery.AttachmentColumns), titleField: 'name', pageSize: 5, ...localeOfData })],
39
+ activity: [component('request-comments', 'activityFeed', { label: 'Comments', entries: fromQuery(ApprovalsQuery.Comments), ...localeOfData })],
40
+ aside: [],
41
+ },
42
+ displayName: 'Request page',
43
+ description: 'One request: summary, approval chain, fields, attachments and comments, and the decision buttons.',
44
+ metadata: approvalsMetadata('RequestPage', 'Detail', [TemplateScope.Feature, TemplateScope.Subfeature]),
45
+ };
@@ -0,0 +1,33 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ScreenTemplate, TemplateScope } from '@cratis/scene.model';
5
+ import { wizardScreenTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ApprovalsQuery, fromQuery, localeOfData } from '../approvalsQueries';
7
+ import { approvalsMetadata, component } from '../approvalsParts';
8
+
9
+ /**
10
+ * The new-request wizard (the foundation `WizardScreen`): **request type**, **details**, **attachments**, then **review and submit**. The type chooses what the
11
+ * details ask for; an invalid step blocks Next and says why; the step the person has reached and the steps they have done survive a refresh, and a refresh can
12
+ * never land past a step that was not done. Save draft keeps the request as a draft in My requests. The step's content is the slot named by its id.
13
+ */
14
+ export const newRequestWizardTemplate: ScreenTemplate = {
15
+ name: 'NewRequestWizard',
16
+ fitsSlot: 'content',
17
+ slots: wizardScreenTemplate.slots,
18
+ arrangement: wizardScreenTemplate.arrangement,
19
+ content: {
20
+ header: [component('request-wizard-header', 'pageHeader', { title: 'New request', subtitle: 'Four short steps' })],
21
+ progress: [component('request-wizard-progress', 'wizardProgress', { steps: fromQuery(ApprovalsQuery.WizardSteps), urlKey: 'step' }, {
22
+ type: [component('request-wizard-type', 'formScreenBody', { mode: 'create', sections: fromQuery(ApprovalsQuery.TypeSections), errors: fromQuery(ApprovalsQuery.FormErrors, '0'), ...localeOfData })],
23
+ details: [component('request-wizard-details', 'formScreenBody', { mode: 'create', sections: fromQuery(ApprovalsQuery.DetailSections), errors: fromQuery(ApprovalsQuery.FormErrors, '0'), ...localeOfData })],
24
+ attachments: [component('request-wizard-attachments', 'fileUploader', { accept: '.pdf, .png, .jpg, .docx, .xlsx', maxSizeMb: 10, multiple: true, actionPermission: 'enabled' })],
25
+ review: [component('request-wizard-review', 'formScreenBody', { mode: 'readOnly', sections: fromQuery(ApprovalsQuery.ReviewSections), values: fromQuery(ApprovalsQuery.ReviewValues, '0'), ...localeOfData })],
26
+ })],
27
+ step: [],
28
+ actions: [],
29
+ },
30
+ displayName: 'New request',
31
+ description: 'Request type, details, attachments, then review and submit; the step survives a refresh and a draft can be saved.',
32
+ metadata: approvalsMetadata('NewRequestWizard', 'Wizard', [TemplateScope.Feature, TemplateScope.Subfeature]),
33
+ };
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="All requests">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="94" y="48" width="60" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="94" y="70" width="206" height="6" rx="3" fill="#9aa3b2"/>
8
+ <rect x="94" y="87" width="170" height="6" rx="3" fill="#9aa3b2"/>
9
+ <rect x="94" y="104" width="206" height="6" rx="3" fill="#9aa3b2"/>
10
+ <rect x="94" y="121" width="170" height="6" rx="3" fill="#9aa3b2"/>
11
+ <rect x="94" y="138" width="206" height="6" rx="3" fill="#9aa3b2"/>
12
+ <rect x="94" y="155" width="170" height="6" rx="3" fill="#9aa3b2"/>
13
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Approval inbox">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="52" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="88" y="46" width="30" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="88" y="60" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="88" y="100" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="141" y="40" width="52" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="145" y="46" width="30" height="6" rx="3" fill="#4f46e5"/>
11
+ <rect x="145" y="60" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
12
+ <rect x="145" y="100" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
13
+ <rect x="145" y="140" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
14
+ <rect x="198" y="40" width="52" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
15
+ <rect x="202" y="46" width="30" height="6" rx="3" fill="#4f46e5"/>
16
+ <rect x="202" y="60" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
17
+ <rect x="202" y="100" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
18
+ <rect x="255" y="40" width="52" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
19
+ <rect x="259" y="46" width="30" height="6" rx="3" fill="#4f46e5"/>
20
+ <rect x="259" y="60" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
21
+ <rect x="259" y="100" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
22
+ <rect x="259" y="140" width="44" height="32" rx="4" fill="#ffffff" stroke="#d5d9df"/>
23
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Your decision">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="12" y="40" width="296" height="148" fill="#000000" fill-opacity="0.15"/>
6
+ <rect x="96" y="56" width="128" height="118" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="104" y="64" width="60" height="6" rx="3" fill="#4f46e5"/>
8
+ <rect x="104" y="82" width="112" height="18" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="104" y="106" width="112" height="18" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="170" y="148" width="46" height="16" rx="4" fill="#4f46e5"/>
11
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="My requests">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="94" y="48" width="60" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="94" y="70" width="206" height="6" rx="3" fill="#9aa3b2"/>
8
+ <rect x="94" y="87" width="170" height="6" rx="3" fill="#9aa3b2"/>
9
+ <rect x="94" y="104" width="206" height="6" rx="3" fill="#9aa3b2"/>
10
+ <rect x="94" y="121" width="170" height="6" rx="3" fill="#9aa3b2"/>
11
+ <rect x="94" y="138" width="206" height="6" rx="3" fill="#9aa3b2"/>
12
+ <rect x="94" y="155" width="170" height="6" rx="3" fill="#9aa3b2"/>
13
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="New request">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="94" y="48" width="70" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="94" y="64" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="200" y="64" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="94" y="98" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="200" y="98" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
11
+ <rect x="94" y="132" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
12
+ <rect x="200" y="132" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
13
+ <rect x="240" y="166" width="58" height="16" rx="4" fill="#4f46e5"/>
14
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Request page">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="28" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="84" y="76" width="70" height="46" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="160" y="76" width="70" height="46" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="236" y="76" width="72" height="46" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="84" y="130" width="150" height="58" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="240" y="130" width="68" height="58" rx="4" fill="#ffffff" stroke="#d5d9df"/>
11
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Edit request type">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="94" y="48" width="70" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="94" y="64" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="200" y="64" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="94" y="98" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="200" y="98" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
11
+ <rect x="94" y="132" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
12
+ <rect x="200" y="132" width="98" height="22" rx="4" fill="#ffffff" stroke="#d5d9df"/>
13
+ <rect x="240" y="166" width="58" height="16" rx="4" fill="#4f46e5"/>
14
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="New request type">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="12" y="40" width="296" height="148" fill="#000000" fill-opacity="0.15"/>
6
+ <rect x="96" y="56" width="128" height="118" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="104" y="64" width="60" height="6" rx="3" fill="#4f46e5"/>
8
+ <rect x="104" y="82" width="112" height="18" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="104" y="106" width="112" height="18" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="170" y="148" width="46" height="16" rx="4" fill="#4f46e5"/>
11
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Request types">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="94" y="48" width="60" height="6" rx="3" fill="#4f46e5"/>
7
+ <rect x="94" y="70" width="206" height="6" rx="3" fill="#9aa3b2"/>
8
+ <rect x="94" y="87" width="170" height="6" rx="3" fill="#9aa3b2"/>
9
+ <rect x="94" y="104" width="206" height="6" rx="3" fill="#9aa3b2"/>
10
+ <rect x="94" y="121" width="170" height="6" rx="3" fill="#9aa3b2"/>
11
+ <rect x="94" y="138" width="206" height="6" rx="3" fill="#9aa3b2"/>
12
+ <rect x="94" y="155" width="170" height="6" rx="3" fill="#9aa3b2"/>
13
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="Approvals blueprint">
2
+ <rect width="320" height="200" rx="8" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#4f46e5"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="224" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="84" y="78" width="224" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="84" y="116" width="224" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="84" y="154" width="224" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ </svg>