@cratis/scene.blueprint.contracts 0.0.0-stage → 4.78.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.
Files changed (132) hide show
  1. package/README.md +69 -2
  2. package/blueprint.ts +16 -0
  3. package/blueprintCatalog.json +107 -0
  4. package/contractsApplication.ts +28 -0
  5. package/contractsParts.ts +58 -0
  6. package/contractsQueries.ts +56 -0
  7. package/contractsScreenSet.ts +21 -0
  8. package/dist/cjs/blueprint.js +19 -0
  9. package/dist/cjs/blueprint.js.map +1 -0
  10. package/dist/cjs/contractsApplication.js +49 -0
  11. package/dist/cjs/contractsApplication.js.map +1 -0
  12. package/dist/cjs/contractsParts.js +151 -0
  13. package/dist/cjs/contractsParts.js.map +1 -0
  14. package/dist/cjs/contractsQueries.js +64 -0
  15. package/dist/cjs/contractsQueries.js.map +1 -0
  16. package/dist/cjs/contractsScreenSet.js +40 -0
  17. package/dist/cjs/contractsScreenSet.js.map +1 -0
  18. package/dist/cjs/index.js +68 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/manifest.js +88 -0
  21. package/dist/cjs/manifest.js.map +1 -0
  22. package/dist/cjs/navigation.js +109 -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 +22 -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 +50 -0
  32. package/dist/cjs/templates/formTemplates.js.map +1 -0
  33. package/dist/cjs/templates/inboxTemplate.js +55 -0
  34. package/dist/cjs/templates/inboxTemplate.js.map +1 -0
  35. package/dist/cjs/templates/index.js +25 -0
  36. package/dist/cjs/templates/index.js.map +1 -0
  37. package/dist/cjs/templates/listTemplates.js +145 -0
  38. package/dist/cjs/templates/listTemplates.js.map +1 -0
  39. package/dist/cjs/templates/recordTemplates.js +135 -0
  40. package/dist/cjs/templates/recordTemplates.js.map +1 -0
  41. package/dist/cjs/templates/timelineTemplate.js +85 -0
  42. package/dist/cjs/templates/timelineTemplate.js.map +1 -0
  43. package/dist/esm/blueprint.d.ts +3 -0
  44. package/dist/esm/blueprint.d.ts.map +1 -0
  45. package/dist/esm/blueprint.js +17 -0
  46. package/dist/esm/blueprint.js.map +1 -0
  47. package/dist/esm/contractsApplication.d.ts +10 -0
  48. package/dist/esm/contractsApplication.d.ts.map +1 -0
  49. package/dist/esm/contractsApplication.js +44 -0
  50. package/dist/esm/contractsApplication.js.map +1 -0
  51. package/dist/esm/contractsParts.d.ts +16 -0
  52. package/dist/esm/contractsParts.d.ts.map +1 -0
  53. package/dist/esm/contractsParts.js +133 -0
  54. package/dist/esm/contractsParts.js.map +1 -0
  55. package/dist/esm/contractsQueries.d.ts +38 -0
  56. package/dist/esm/contractsQueries.d.ts.map +1 -0
  57. package/dist/esm/contractsQueries.js +56 -0
  58. package/dist/esm/contractsQueries.js.map +1 -0
  59. package/dist/esm/contractsScreenSet.d.ts +7 -0
  60. package/dist/esm/contractsScreenSet.d.ts.map +1 -0
  61. package/dist/esm/contractsScreenSet.js +38 -0
  62. package/dist/esm/contractsScreenSet.js.map +1 -0
  63. package/dist/esm/index.d.ts +12 -0
  64. package/dist/esm/index.d.ts.map +1 -0
  65. package/dist/esm/index.js +18 -0
  66. package/dist/esm/index.js.map +1 -0
  67. package/dist/esm/manifest.d.ts +3 -0
  68. package/dist/esm/manifest.d.ts.map +1 -0
  69. package/dist/esm/manifest.js +86 -0
  70. package/dist/esm/manifest.js.map +1 -0
  71. package/dist/esm/navigation.d.ts +5 -0
  72. package/dist/esm/navigation.d.ts.map +1 -0
  73. package/dist/esm/navigation.js +105 -0
  74. package/dist/esm/navigation.js.map +1 -0
  75. package/dist/esm/package.json +3 -0
  76. package/dist/esm/packageName.d.ts +2 -0
  77. package/dist/esm/packageName.d.ts.map +1 -0
  78. package/dist/esm/packageName.js +6 -0
  79. package/dist/esm/packageName.js.map +1 -0
  80. package/dist/esm/screens/index.d.ts +3 -0
  81. package/dist/esm/screens/index.d.ts.map +1 -0
  82. package/dist/esm/screens/index.js +20 -0
  83. package/dist/esm/screens/index.js.map +1 -0
  84. package/dist/esm/templateProvenance.d.ts +3 -0
  85. package/dist/esm/templateProvenance.d.ts.map +1 -0
  86. package/dist/esm/templateProvenance.js +22 -0
  87. package/dist/esm/templateProvenance.js.map +1 -0
  88. package/dist/esm/templates/formTemplates.d.ts +3 -0
  89. package/dist/esm/templates/formTemplates.d.ts.map +1 -0
  90. package/dist/esm/templates/formTemplates.js +48 -0
  91. package/dist/esm/templates/formTemplates.js.map +1 -0
  92. package/dist/esm/templates/inboxTemplate.d.ts +3 -0
  93. package/dist/esm/templates/inboxTemplate.d.ts.map +1 -0
  94. package/dist/esm/templates/inboxTemplate.js +53 -0
  95. package/dist/esm/templates/inboxTemplate.js.map +1 -0
  96. package/dist/esm/templates/index.d.ts +8 -0
  97. package/dist/esm/templates/index.d.ts.map +1 -0
  98. package/dist/esm/templates/index.js +17 -0
  99. package/dist/esm/templates/index.js.map +1 -0
  100. package/dist/esm/templates/listTemplates.d.ts +3 -0
  101. package/dist/esm/templates/listTemplates.d.ts.map +1 -0
  102. package/dist/esm/templates/listTemplates.js +143 -0
  103. package/dist/esm/templates/listTemplates.js.map +1 -0
  104. package/dist/esm/templates/recordTemplates.d.ts +3 -0
  105. package/dist/esm/templates/recordTemplates.d.ts.map +1 -0
  106. package/dist/esm/templates/recordTemplates.js +133 -0
  107. package/dist/esm/templates/recordTemplates.js.map +1 -0
  108. package/dist/esm/templates/timelineTemplate.d.ts +3 -0
  109. package/dist/esm/templates/timelineTemplate.d.ts.map +1 -0
  110. package/dist/esm/templates/timelineTemplate.js +83 -0
  111. package/dist/esm/templates/timelineTemplate.js.map +1 -0
  112. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  113. package/index.ts +14 -0
  114. package/manifest.ts +41 -0
  115. package/navigation.ts +53 -0
  116. package/package.json +78 -4
  117. package/packageName.ts +5 -0
  118. package/sampleData/contracts-en.json +892 -0
  119. package/screens/index.ts +20 -0
  120. package/templateProvenance.ts +15 -0
  121. package/templates/formTemplates.ts +33 -0
  122. package/templates/inboxTemplate.ts +24 -0
  123. package/templates/index.ts +18 -0
  124. package/templates/listTemplates.ts +96 -0
  125. package/templates/recordTemplates.ts +78 -0
  126. package/templates/timelineTemplate.ts +54 -0
  127. package/thumbnails/ContractPage.svg +17 -0
  128. package/thumbnails/ContractsList.svg +29 -0
  129. package/thumbnails/ContractsQuickCreateContract.svg +12 -0
  130. package/thumbnails/ContractsReview.svg +19 -0
  131. package/thumbnails/ContractsTimeline.svg +11 -0
  132. package/thumbnails/contracts.svg +14 -0
@@ -0,0 +1,20 @@
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 { contractsScreenDefinitions } from '../contractsScreenSet';
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
10
+ * the foundation's application shell. A new application that adopts the blueprint gets these, wired into its navigation (`contractsNavigation`).
11
+ */
12
+ export const contractsScreens: Screen[] = contractsScreenDefinitions.map(definition => ({
13
+ name: definition.name,
14
+ layout: LayoutName.AppShell,
15
+ screenTemplate: definition.template,
16
+ slotContent: {},
17
+ forms: [],
18
+ contributions: [],
19
+ path: definition.name.split('.'),
20
+ }));
@@ -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 contractsTemplateProvenance: 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.contracts' },
13
+ license: 'MIT',
14
+ licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE',
15
+ };
@@ -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 { DialogTemplate, TemplateScope } from '@cratis/scene.model';
5
+ import { quickCreateDialogTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ContractsQuery, fromQuery, localeOfData } from '../contractsQueries';
7
+ import { closesDialog, component, contractsMetadata, withBehaviors } from '../contractsParts';
8
+
9
+ /**
10
+ * One quick-create dialog: the foundation `QuickCreateDialog` - a short form opened from a page to make one record without leaving it - with the fields
11
+ * that thing needs to get started.
12
+ */
13
+ function quickCreateOf(name: string, title: string, sections: string, noun: string, submit: string): DialogTemplate {
14
+ return {
15
+ name,
16
+ slots: quickCreateDialogTemplate.slots,
17
+ content: {
18
+ header: [component(`${name}-frame`, 'dialogFrame', { title, subtitle: 'Only what is needed to get started' })],
19
+ body: [withBehaviors(component(`${name}-form`, 'formScreenBody', {
20
+ mode: 'create', saveAndNew: false, strings: { formSave: submit }, sections: fromQuery(sections), errors: fromQuery(ContractsQuery.FormErrors, '0'), ...localeOfData,
21
+ }), closesDialog())],
22
+ actions: [],
23
+ },
24
+ displayName: `Contracts quick create ${noun}`,
25
+ description: `A short form that creates one ${noun} without leaving the page.`,
26
+ metadata: contractsMetadata(name, 'Dialog', [TemplateScope.Slice]),
27
+ };
28
+ }
29
+
30
+ /** The quick dialogs of the blueprint. */
31
+ export const contractsDialogs: DialogTemplate[] = [
32
+ quickCreateOf('ContractsQuickCreateContract', 'New contract', 'ContractQuickSections', 'contract', 'Create'),
33
+ ];
@@ -0,0 +1,24 @@
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 { inboxScreenTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ContractsQuery, fromQuery, localeOfData } from '../contractsQueries';
7
+ import { contractsMetadata, component } from '../contractsParts';
8
+
9
+ /** The review inbox: the contracts that need a review, a signature or a renewal decision, the open message beside them and its history beneath. */
10
+ export const contractsReviewTemplate: ScreenTemplate = {
11
+ name: 'ContractsReview',
12
+ fitsSlot: 'content',
13
+ slots: inboxScreenTemplate.slots,
14
+ arrangement: inboxScreenTemplate.arrangement,
15
+ content: {
16
+ header: [component('ContractsReview-header', 'pageHeader', { title: 'Needs attention', subtitle: 'Review, sign or renew' })],
17
+ queue: [component('ContractsReview-queue', 'inboxList', { label: 'Needs attention', messages: fromQuery(ContractsQuery.ContractMessages), urlKey: 'msg', ...localeOfData })],
18
+ message: [component('ContractsReview-message', 'formScreenBody', { mode: 'readOnly', sections: fromQuery(ContractsQuery.ContractMessageSections), values: fromQuery(ContractsQuery.ContractMessageValues, '0'), ...localeOfData })],
19
+ history: [component('ContractsReview-history', 'activityFeed', { label: 'History', entries: fromQuery(ContractsQuery.ContractMessageHistory), ...localeOfData })],
20
+ },
21
+ displayName: 'Contracts review inbox',
22
+ description: 'What needs review, signature or a renewal decision: the queue grouped by day with unread told in words, the open message and its history.',
23
+ metadata: contractsMetadata('ContractsReview', 'Inbox', [TemplateScope.Module, TemplateScope.Feature]),
24
+ };
@@ -0,0 +1,18 @@
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 { contractsListTemplate } from './listTemplates';
5
+ import { contractPageTemplate } from './recordTemplates';
6
+ import { contractsTimelineTemplate } from './timelineTemplate';
7
+ import { contractsReviewTemplate } from './inboxTemplate';
8
+
9
+ export * from './listTemplates';
10
+ export * from './recordTemplates';
11
+ export * from './timelineTemplate';
12
+ export * from './inboxTemplate';
13
+ export * from './formTemplates';
14
+
15
+ /** Every screen template this blueprint provides, in the order the manifest lists them. */
16
+ export const contractsScreenTemplates = [contractsListTemplate, contractPageTemplate, contractsTimelineTemplate, contractsReviewTemplate];
17
+
18
+ export { contractsDialogs as contractsDialogTemplates } from './formTemplates';
@@ -0,0 +1,96 @@
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 { ContractsEntityKind, fromQuery, contractsQueriesOf, localeOfData } from '../contractsQueries';
7
+ import { actionButton, component, goesTo, contractsMetadata, opensDialog, opensDialogOnSelect, opensRecordOnSelect, withBehaviors } from '../contractsParts';
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
+ entity: ContractsEntityKind;
22
+ displayName: string;
23
+ description: string;
24
+ title: string;
25
+ subtitle: string;
26
+ searchLabel: string;
27
+ urlKey: string;
28
+ /** The primary action of the header: a quick-create dialog to open, or a screen to go to. */
29
+ primary: { label: string; dialog?: string; screen?: string };
30
+ rowActions: string[];
31
+ bulkActions: string[];
32
+ titleField: string;
33
+ /** The screen a chosen row opens; the list then selects one row at a time. Absent, rows are selected many at a time for the bulk bar. */
34
+ recordScreen?: string;
35
+ /** The side sheet a chosen row opens instead of a record page; the list then selects one row at a time. */
36
+ recordDialog?: string;
37
+ /** Group the rows (`variant: grouped`) by this field. */
38
+ grouped?: { groupBy: string };
39
+ /** Rows are not selectable at all: a record of what happened, which nobody edits. */
40
+ readOnly?: boolean;
41
+ /** Show the records as cards, each with the picture its `imageField` names. */
42
+ cards?: { imageField?: string };
43
+ /** Tint a row by the tone in this field (always beside a status column that says the same in words). */
44
+ toneField?: string;
45
+ }
46
+
47
+ /**
48
+ * One list: the foundation `ListScreen` with its header, toolbar, filters, list and bulk bar filled for an entity. The slots, arrangement and
49
+ * every behavior - sort, search, paging and selection in the address, the table collapsing to cards on a phone - are the foundation's.
50
+ */
51
+ function listTemplateOf(options: ListOptions): ScreenTemplate {
52
+ const queries = contractsQueriesOf(options.entity);
53
+ const id = options.name;
54
+ const listId = `${id}-records`;
55
+ const primary = withBehaviors(actionButton(`${id}-primary`, options.primary.label, 'primary'), options.primary.dialog ? opensDialog(options.primary.dialog) : goesTo(options.primary.screen!));
56
+ const list = component(listId, 'dataList', {
57
+ label: options.title, rows: fromQuery(queries.rows), columns: fromQuery(queries.columns), titleField: options.titleField, pageSize: options.cards ? 12 : 10, urlKey: options.urlKey, ...localeOfData,
58
+ rowActions: options.rowActions,
59
+ ...(options.readOnly ? {} : { selectionMode: options.recordScreen || options.recordDialog ? 'single' : 'multiple' }),
60
+ ...(options.cards ? { variant: 'cards', ...(options.cards.imageField ? { imageField: options.cards.imageField } : {}) } : {}),
61
+ ...(options.grouped ? { variant: 'grouped', groupBy: options.grouped.groupBy } : {}),
62
+ ...(options.toneField ? { toneField: options.toneField } : {}),
63
+ });
64
+
65
+ return {
66
+ name: options.name,
67
+ fitsSlot: 'content',
68
+ slots: listScreenTemplate.slots,
69
+ arrangement: listScreenTemplate.arrangement,
70
+ content: {
71
+ header: [component(`${id}-header`, 'pageHeader', { title: options.title, subtitle: options.subtitle }, { actions: [exportAction(`${id}-export`), primary] })],
72
+ toolbar: [
73
+ component(`${id}-search`, 'globalSearch', { placeholder: options.searchLabel, label: options.searchLabel, urlKey: `${options.urlKey}q` }),
74
+ component(`${id}-views`, 'savedViewsMenu', { views: fromQuery(queries.views), savePermission: 'enabled', managePermission: 'enabled' }),
75
+ component(`${id}-columns`, 'columnChooser', { columns: fromQuery(queries.columnChoices) }),
76
+ ],
77
+ filters: [component(`${id}-filter`, 'filterBuilder', { fields: fromQuery(queries.filterFields), ...localeOfData })],
78
+ list: [options.recordScreen ? withBehaviors(list, opensRecordOnSelect(listId, options.recordScreen)) : options.recordDialog ? withBehaviors(list, opensDialogOnSelect(options.recordDialog)) : list],
79
+ bulkBar: options.recordScreen || options.recordDialog || options.readOnly ? [] : [component(`${id}-bulk`, 'bulkBar', { selection: fromQuery(queries.selection), actions: options.bulkActions })],
80
+ footer: [],
81
+ },
82
+ displayName: options.displayName,
83
+ description: options.description,
84
+ metadata: contractsMetadata(options.name, 'List', listScopes),
85
+ };
86
+ }
87
+
88
+
89
+ /** The contracts: every contract with its counterparty, type, end date, value and status. Choosing a contract opens it. */
90
+ export const contractsListTemplate = listTemplateOf({
91
+ name: 'ContractsList',
92
+ entity: ContractsEntityKind.Contract, displayName: 'Contracts list', description: 'Every contract with its counterparty, type, end date, value and status, filtered by status, type, owner and date.', title: 'Contracts', subtitle: 'Every agreement you are bound by', searchLabel: 'Search contracts', urlKey: 'contracts',
93
+ primary: { label: 'New contract', dialog: 'ContractsQuickCreateContract' },
94
+ rowActions: ['Open', 'Start renewal'], bulkActions: [],
95
+ titleField: 'title', recordScreen: 'contracts.record'
96
+ });
@@ -0,0 +1,78 @@
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 { ContractsEntityKind, currencyOfData, fromQuery, localeOfData, contractsQueriesOf } from '../contractsQueries';
7
+ import { actionButton, component, goesTo, contractsMetadata, opensDialog, withBehaviors } from '../contractsParts';
8
+
9
+ interface Fact { id: string; label: string; field: string; format?: 'currency' | 'percent' }
10
+ interface Extra { key: string; label: string; titleField: string; pageSize?: number }
11
+ interface Action { id: string; label: string; emphasis: 'primary' | 'secondary' | 'quiet' | 'danger'; dialog?: string; screen?: string }
12
+
13
+ interface RecordOptions {
14
+ name: string;
15
+ entity: ContractsEntityKind;
16
+ displayName: string;
17
+ description: string;
18
+ titleField: string;
19
+ backScreen: string;
20
+ backLabel: string;
21
+ facts: Fact[];
22
+ extras: Extra[];
23
+ actions: Action[];
24
+ }
25
+
26
+ /**
27
+ * One record page: the foundation `RecordPage` with the record's own title, its status and key facts at the top, its fields and the lists that belong to it in the
28
+ * main region, and the activity beside it. What it shows is the record the list handed it the id of.
29
+ */
30
+ function recordPageOf(options: RecordOptions): ScreenTemplate {
31
+ const queries = contractsQueriesOf(options.entity);
32
+ const id = options.name;
33
+ return {
34
+ name: options.name,
35
+ fitsSlot: 'content',
36
+ slots: recordPageTemplate.slots,
37
+ arrangement: recordPageTemplate.arrangement,
38
+ content: {
39
+ header: [component(`${id}-header`, 'pageHeader', { title: fromQuery(queries.record, `0.${options.titleField}`), subtitle: fromQuery(queries.record, '0.summary') }, {
40
+ actions: [
41
+ withBehaviors(actionButton(`${id}-back`, options.backLabel, 'secondary'), goesTo(options.backScreen)),
42
+ ...options.actions.map(action => withBehaviors(actionButton(`${id}-${action.id}`, action.label, action.emphasis), action.dialog ? opensDialog(action.dialog) : goesTo(action.screen!))),
43
+ ],
44
+ })],
45
+ summary: [
46
+ component(`${id}-status`, 'statusChip', { status: fromQuery(queries.summary, '0.status'), tone: fromQuery(queries.summary, '0.tone') }),
47
+ ...options.facts.map(fact => component(`${id}-${fact.id}`, 'statCard', {
48
+ label: fact.label, value: fromQuery(queries.summary, `0.${fact.field}`), ...(fact.format ? { format: fact.format } : {}), ...currencyOfData,
49
+ })),
50
+ ],
51
+ tabs: [component(`${id}-tabs`, 'tabSet', { tabs: fromQuery(queries.tabs), urlKey: 'tab', label: `${options.displayName} sections` })],
52
+ main: [
53
+ component(`${id}-form`, 'formScreenBody', { mode: 'readOnly', sections: fromQuery(queries.sections), values: fromQuery(queries.record, '0'), ...currencyOfData }),
54
+ ...options.extras.map(extra => component(`${id}-${extra.key.toLowerCase()}`, 'dataList', {
55
+ label: extra.label, rows: fromQuery(`${options.entity}${extra.key}`), columns: fromQuery(`${options.entity}${extra.key}Columns`), titleField: extra.titleField, pageSize: extra.pageSize ?? 8, ...currencyOfData,
56
+ })),
57
+ ],
58
+ related: [],
59
+ activity: [component(`${id}-activity`, 'activityFeed', { label: 'Activity', entries: fromQuery(queries.activity), ...localeOfData })],
60
+ aside: [],
61
+ },
62
+ displayName: options.displayName,
63
+ description: options.description,
64
+ metadata: contractsMetadata(options.name, 'Detail', [TemplateScope.Feature, TemplateScope.Subfeature]),
65
+ };
66
+ }
67
+
68
+ /** The contract page: the contract number as its title, its status, value, days to its end and notice period at the top, its details, parties, obligations and amendments in the main region, and the activity beside it. */
69
+ export const contractPageTemplate = recordPageOf({
70
+ name: 'ContractPage', entity: ContractsEntityKind.Contract, displayName: 'Contract page', description: 'One contract: status, value, days to its end and notice period, its details, parties, obligations and amendments, and its activity.', titleField: 'number', backScreen: 'contracts.list', backLabel: 'Back to contracts',
71
+ facts: [
72
+ { id: 'value', label: 'Contract value', field: 'value', format: 'currency' },
73
+ { id: 'days', label: 'Days to end', field: 'daysToEnd' },
74
+ { id: 'notice', label: 'Notice (days)', field: 'noticeDays' },
75
+ ],
76
+ extras: [{ key: 'Parties', label: 'Parties', titleField: 'name' }, { key: 'Obligations', label: 'Obligations', titleField: 'summary' }, { key: 'Amendments', label: 'Amendments', titleField: 'number' }],
77
+ actions: [],
78
+ });
@@ -0,0 +1,54 @@
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 { timelineScreenTemplate } from '@cratis/scene.blueprint.default';
6
+ import { ContractsQuery, fromQuery, localeOfData } from '../contractsQueries';
7
+ import { actionButton, component, goesTo, contractsMetadata, withBehaviors } from '../contractsParts';
8
+
9
+ interface TimelineOptions {
10
+ name: string;
11
+ displayName: string;
12
+ description: string;
13
+ title: string;
14
+ subtitle: string;
15
+ label: string;
16
+ listLabel: string;
17
+ searchLabel: string;
18
+ items: string;
19
+ columns: string;
20
+ back: { label: string; screen: string };
21
+ }
22
+
23
+ /**
24
+ * One timeline: the foundation `TimelineScreen` with every item as a bar in a lane, how far along it is, the milestones, what waits on what, and a conflict told in
25
+ * words when one lane's bars overlap. The scale is kept in the address; on a phone the schedule is the table, and the same items are listed beneath.
26
+ */
27
+ function timelineOf(options: TimelineOptions): ScreenTemplate {
28
+ const id = options.name;
29
+ return {
30
+ name: options.name,
31
+ fitsSlot: 'content',
32
+ slots: timelineScreenTemplate.slots,
33
+ arrangement: timelineScreenTemplate.arrangement,
34
+ content: {
35
+ header: [component(`${id}-header`, 'pageHeader', { title: options.title, subtitle: options.subtitle }, {
36
+ actions: [withBehaviors(actionButton(`${id}-back`, options.back.label, 'secondary'), goesTo(options.back.screen))],
37
+ })],
38
+ toolbar: [component(`${id}-search`, 'globalSearch', { placeholder: options.searchLabel, label: options.searchLabel, urlKey: 'timelineq' })],
39
+ timeline: [component(`${id}-grid`, 'timelineGrid', {
40
+ label: options.label, items: fromQuery(options.items), today: fromQuery(ContractsQuery.Settings, '0.today'), firstDay: fromQuery(ContractsQuery.Settings, '0.firstDay'), urlKey: 'scale', ...localeOfData,
41
+ })],
42
+ list: [component(`${id}-list`, 'dataList', { label: options.listLabel, rows: fromQuery(options.items), columns: fromQuery(options.columns), titleField: 'title', pageSize: 8, ...localeOfData })],
43
+ },
44
+ displayName: options.displayName,
45
+ description: options.description,
46
+ metadata: contractsMetadata(options.name, 'Timeline', [TemplateScope.Module, TemplateScope.Feature]),
47
+ };
48
+ }
49
+
50
+ /** The contracts timeline: each live contract as a bar in a lane for its counterparty, how far through its term it is, and a milestone for each notice date; the list beneath names the same terms. */
51
+ export const contractsTimelineTemplate = timelineOf({
52
+ name: 'ContractsTimeline', displayName: 'Contracts timeline', description: 'Every live contract as a bar from start to end in a lane for each counterparty, with how far through it is and the notice dates that matter.', title: 'Timeline', subtitle: 'Terms and notice dates by counterparty', label: 'Contract terms', listLabel: 'Terms',
53
+ searchLabel: 'Search the timeline', items: ContractsQuery.ContractTimelineItems, columns: ContractsQuery.ContractTimelineColumns, back: { label: 'Open the contracts', screen: 'contracts.list' },
54
+ });
@@ -0,0 +1,17 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="ContractPage">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="160" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="236" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="84" y="78" width="150" height="110" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="242" y="78" width="66" height="110" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="94" y="90" width="130" height="6" rx="3" fill="#9aa3b2"/>
11
+ <rect x="94" y="107" width="130" height="6" rx="3" fill="#9aa3b2"/>
12
+ <rect x="94" y="124" width="130" height="6" rx="3" fill="#9aa3b2"/>
13
+ <rect x="94" y="141" width="130" height="6" rx="3" fill="#9aa3b2"/>
14
+ <rect x="250" y="90" width="50" height="6" rx="3" fill="#b45309"/>
15
+ <rect x="250" y="107" width="50" height="6" rx="3" fill="#b45309"/>
16
+ <rect x="250" y="124" width="50" height="6" rx="3" fill="#b45309"/>
17
+ </svg>
@@ -0,0 +1,29 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="ContractsList">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="88" y="44" width="60" height="30" rx="4" fill="#d5d9df"/>
7
+ <rect x="90" y="82" width="40" height="5" rx="3" fill="#b45309"/>
8
+ <rect x="90" y="94" width="52" height="5" rx="3" fill="#9aa3b2"/>
9
+ <rect x="160" y="40" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="164" y="44" width="60" height="30" rx="4" fill="#d5d9df"/>
11
+ <rect x="166" y="82" width="40" height="5" rx="3" fill="#b45309"/>
12
+ <rect x="166" y="94" width="52" height="5" rx="3" fill="#9aa3b2"/>
13
+ <rect x="236" y="40" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
14
+ <rect x="240" y="44" width="60" height="30" rx="4" fill="#d5d9df"/>
15
+ <rect x="242" y="82" width="40" height="5" rx="3" fill="#b45309"/>
16
+ <rect x="242" y="94" width="52" height="5" rx="3" fill="#9aa3b2"/>
17
+ <rect x="84" y="116" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
18
+ <rect x="88" y="120" width="60" height="30" rx="4" fill="#d5d9df"/>
19
+ <rect x="90" y="158" width="40" height="5" rx="3" fill="#b45309"/>
20
+ <rect x="90" y="170" width="52" height="5" rx="3" fill="#9aa3b2"/>
21
+ <rect x="160" y="116" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
22
+ <rect x="164" y="120" width="60" height="30" rx="4" fill="#d5d9df"/>
23
+ <rect x="166" y="158" width="40" height="5" rx="3" fill="#b45309"/>
24
+ <rect x="166" y="170" width="52" height="5" rx="3" fill="#9aa3b2"/>
25
+ <rect x="236" y="116" width="68" height="70" rx="4" fill="#ffffff" stroke="#d5d9df"/>
26
+ <rect x="240" y="120" width="60" height="30" rx="4" fill="#d5d9df"/>
27
+ <rect x="242" y="158" width="40" height="5" rx="3" fill="#b45309"/>
28
+ <rect x="242" y="170" width="52" height="5" rx="3" fill="#9aa3b2"/>
29
+ </svg>
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="ContractsQuickCreateContract">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
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="#e4e7ec"/>
6
+ <rect x="120" y="56" width="152" height="120" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="130" y="66" width="70" height="7" rx="3" fill="#b45309"/>
8
+ <rect x="130" y="86" width="132" height="14" rx="4" fill="#eef0f3"/>
9
+ <rect x="130" y="108" width="132" height="14" rx="4" fill="#eef0f3"/>
10
+ <rect x="130" y="130" width="132" height="14" rx="4" fill="#eef0f3"/>
11
+ <rect x="206" y="152" width="56" height="16" rx="4" fill="#b45309"/>
12
+ </svg>
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="200" viewBox="0 0 320 200" role="img" aria-label="ContractsReview">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="90" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="182" y="40" width="126" height="148" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="90" y="50" width="78" height="26" rx="4" fill="#eef0f3" stroke="#d5d9df"/>
8
+ <rect x="94" y="58" width="40" height="5" rx="3" fill="#b45309"/>
9
+ <rect x="90" y="82" width="78" height="26" rx="4" fill="#ffffff" stroke="#d5d9df"/>
10
+ <rect x="94" y="90" width="40" height="5" rx="3" fill="#b45309"/>
11
+ <rect x="90" y="114" width="78" height="26" rx="4" fill="#ffffff" stroke="#d5d9df"/>
12
+ <rect x="94" y="122" width="40" height="5" rx="3" fill="#b45309"/>
13
+ <rect x="90" y="146" width="78" height="26" rx="4" fill="#ffffff" stroke="#d5d9df"/>
14
+ <rect x="94" y="154" width="40" height="5" rx="3" fill="#b45309"/>
15
+ <rect x="194" y="52" width="100" height="6" rx="3" fill="#9aa3b2"/>
16
+ <rect x="194" y="70" width="100" height="6" rx="3" fill="#9aa3b2"/>
17
+ <rect x="194" y="88" width="100" height="6" rx="3" fill="#9aa3b2"/>
18
+ <rect x="194" y="106" width="100" height="6" rx="3" fill="#9aa3b2"/>
19
+ </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="ContractsTimeline">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
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="96" y="52" width="90" height="14" rx="4" fill="#b45309"/>
7
+ <rect x="130" y="76" width="120" height="14" rx="4" fill="#9aa3b2"/>
8
+ <rect x="110" y="100" width="80" height="14" rx="4" fill="#b45309"/>
9
+ <rect x="170" y="124" width="110" height="14" rx="4" fill="#9aa3b2"/>
10
+ <rect x="100" y="148" width="60" height="14" rx="4" fill="#b45309"/>
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="Contracts blueprint">
2
+ <rect x="0" y="0" width="320" height="200" rx="4" fill="#f4f5f7"/>
3
+ <rect x="12" y="12" width="296" height="20" rx="4" fill="#b45309"/>
4
+ <rect x="12" y="40" width="64" height="148" rx="4" fill="#d5d9df"/>
5
+ <rect x="84" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
6
+ <rect x="160" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
7
+ <rect x="236" y="40" width="70" height="30" rx="4" fill="#ffffff" stroke="#d5d9df"/>
8
+ <rect x="84" y="78" width="224" height="110" rx="4" fill="#ffffff" stroke="#d5d9df"/>
9
+ <rect x="94" y="90" width="200" height="6" rx="3" fill="#9aa3b2"/>
10
+ <rect x="94" y="107" width="164" height="6" rx="3" fill="#9aa3b2"/>
11
+ <rect x="94" y="124" width="200" height="6" rx="3" fill="#9aa3b2"/>
12
+ <rect x="94" y="141" width="164" height="6" rx="3" fill="#9aa3b2"/>
13
+ <rect x="94" y="158" width="200" height="6" rx="3" fill="#9aa3b2"/>
14
+ </svg>