@riboseinc/paneron-registry-kit 2.2.30 → 2.2.32

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 (74) hide show
  1. package/index.js +1 -0
  2. package/index.js.map +1 -1
  3. package/item-classes/Tree.d.ts +5 -0
  4. package/item-classes/Tree.js +115 -0
  5. package/item-classes/Tree.js.map +1 -0
  6. package/item-classes/treeNodes.d.ts +12 -0
  7. package/item-classes/treeNodes.js +68 -0
  8. package/item-classes/treeNodes.js.map +1 -0
  9. package/package.json +2 -2
  10. package/proposals/actionableGroups/Tree.d.ts +7 -0
  11. package/proposals/actionableGroups/Tree.js +179 -0
  12. package/proposals/actionableGroups/Tree.js.map +1 -0
  13. package/proposals/actionableGroups/queries.d.ts +5 -0
  14. package/proposals/actionableGroups/queries.js +81 -0
  15. package/proposals/actionableGroups/queries.js.map +1 -0
  16. package/proposals/actionableGroups/treeNodes.d.ts +26 -0
  17. package/proposals/actionableGroups/treeNodes.js +96 -0
  18. package/proposals/actionableGroups/treeNodes.js.map +1 -0
  19. package/proposals/actionableGroups/types.d.ts +6 -0
  20. package/proposals/actionableGroups/types.js +5 -0
  21. package/proposals/actionableGroups/types.js.map +1 -0
  22. package/types/cr.d.ts +1 -0
  23. package/types/cr.js.map +1 -1
  24. package/types/register.d.ts +4 -1
  25. package/types/register.js.map +1 -1
  26. package/types/stakeholder.d.ts +22 -41
  27. package/types/stakeholder.js +34 -16
  28. package/types/stakeholder.js.map +1 -1
  29. package/types/views.d.ts +2 -0
  30. package/types/views.js.map +1 -1
  31. package/views/BrowserCtx.d.ts +1 -1
  32. package/views/BrowserCtx.js.map +1 -1
  33. package/views/GenericRelatedItemView.js +21 -8
  34. package/views/GenericRelatedItemView.js.map +1 -1
  35. package/views/ItemDetailsDrawer.d.ts +1 -0
  36. package/views/ItemDetailsDrawer.js +4 -2
  37. package/views/ItemDetailsDrawer.js.map +1 -1
  38. package/views/ItemSearchDrawer.js +1 -1
  39. package/views/ItemSearchDrawer.js.map +1 -1
  40. package/views/RegisterStakeholder.js +2 -2
  41. package/views/RegisterStakeholder.js.map +1 -1
  42. package/views/StatefulTree.d.ts +28 -0
  43. package/views/StatefulTree.js +131 -0
  44. package/views/StatefulTree.js.map +1 -0
  45. package/views/change-request/TransitionHistory.js +6 -3
  46. package/views/change-request/TransitionHistory.js.map +1 -1
  47. package/views/change-request/TransitionOptions.js +37 -13
  48. package/views/change-request/TransitionOptions.js.map +1 -1
  49. package/views/detail/RegisterHome/index.js +20 -79
  50. package/views/detail/RegisterHome/index.js.map +1 -1
  51. package/views/detail/RegisterItem/index.d.ts +2 -2
  52. package/views/detail/RegisterItem/index.js +7 -2
  53. package/views/detail/RegisterItem/index.js.map +1 -1
  54. package/views/detail/RegisterItemClass.d.ts +12 -0
  55. package/views/detail/RegisterItemClass.js +98 -0
  56. package/views/detail/RegisterItemClass.js.map +1 -0
  57. package/views/detail/RegisterMeta/RegisterMetaForm.js +272 -114
  58. package/views/detail/RegisterMeta/RegisterMetaForm.js.map +1 -1
  59. package/views/detail/RegisterMeta/index.js +1 -1
  60. package/views/detail/RegisterMeta/index.js.map +1 -1
  61. package/views/index.js +63 -6
  62. package/views/index.js.map +1 -1
  63. package/views/protocolRegistry.d.ts +1 -0
  64. package/views/protocolRegistry.js +4 -0
  65. package/views/protocolRegistry.js.map +1 -1
  66. package/views/sidebar/Browse/index.js +8 -44
  67. package/views/sidebar/Browse/index.js.map +1 -1
  68. package/views/sidebar/Registration/index.js.map +1 -1
  69. package/views/sidebar/index.d.ts +2 -1
  70. package/views/sidebar/index.js +77 -62
  71. package/views/sidebar/index.js.map +1 -1
  72. package/views/util.d.ts +5 -0
  73. package/views/util.js +42 -4
  74. package/views/util.js.map +1 -1
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getActionableProposalGroupsAsTreeNodes = getActionableProposalGroupsAsTreeNodes;
7
+ exports.getMapReduceChainsForActionableProposalGroups = getMapReduceChainsForActionableProposalGroups;
8
+
9
+ var _react = require("@emotion/react");
10
+
11
+ var _core = require("@blueprintjs/core");
12
+
13
+ var _queries = require("./queries");
14
+
15
+ /** @jsx jsx */
16
+
17
+ /** @jsxFrag React.Fragment */
18
+
19
+ /**
20
+ * Tools for rendering proposal groups as tree nodes.
21
+ * Each proposal group is top-level node, with proposals as nested nodes.
22
+ */
23
+ //import React, { useContext, useMemo } from 'react';
24
+ function getActionableProposalGroupsAsTreeNodes(groups, opts) {
25
+ return groups. //filter(({ proposals }) => proposals && proposals.length > 0).
26
+ map(({
27
+ groupLabel,
28
+ proposals
29
+ }) => {
30
+ var _a;
31
+
32
+ const hasProposals = proposals && proposals.length > 0;
33
+ const hasActiveProposal = hasProposals && (opts === null || opts === void 0 ? void 0 : opts.activeCRID) && proposals.find(p => p.id === opts.activeCRID);
34
+ const hasSelectedProposal = hasProposals && (opts === null || opts === void 0 ? void 0 : opts.selectedCRID) && proposals.find(p => p.id === opts.selectedCRID);
35
+ const isExpanded = groups.length === 1 || ((_a = opts === null || opts === void 0 ? void 0 : opts.expandedGroupLabels) === null || _a === void 0 ? void 0 : _a.has(groupLabel)) || hasSelectedProposal ? true : false;
36
+ return {
37
+ id: groupLabel,
38
+ label: groupLabel,
39
+ hasCaret: true,
40
+ secondaryLabel: hasActiveProposal && !isExpanded ? activeCRMarker : (0, _react.jsx)(_core.Tag, {
41
+ minimal: !hasProposals,
42
+ intent: hasProposals ? 'primary' : undefined
43
+ }, hasProposals ? proposals.length : 0),
44
+ icon: isExpanded ? 'folder-open' : 'folder-close',
45
+ isExpanded,
46
+ isSelected: groupLabel === (opts === null || opts === void 0 ? void 0 : opts.selectedGroup),
47
+ nodeData: {
48
+ type: 'group'
49
+ },
50
+ childNodes: hasProposals && isExpanded ? proposals.map(p => getActionableProposalTreeNode(p, {
51
+ isSelected: p.id === (opts === null || opts === void 0 ? void 0 : opts.selectedCRID),
52
+ isActive: p.id === (opts === null || opts === void 0 ? void 0 : opts.activeCRID)
53
+ })) : []
54
+ };
55
+ });
56
+ }
57
+
58
+ const activeCRMarker = (0, _react.jsx)(_core.Tag, {
59
+ intent: 'danger'
60
+ }, "active");
61
+
62
+ function getActionableProposalTreeNode(proposal, opts) {
63
+ var _a;
64
+
65
+ return {
66
+ id: proposal.id,
67
+ label: (0, _react.jsx)("span", {
68
+ title: `Double-click the proposal to activate: “${proposal.justification}”`
69
+ }, proposal.justification),
70
+ isSelected: (_a = opts === null || opts === void 0 ? void 0 : opts.isSelected) !== null && _a !== void 0 ? _a : false,
71
+ icon: 'lightbulb',
72
+ secondaryLabel: (opts === null || opts === void 0 ? void 0 : opts.isActive) ? activeCRMarker : undefined,
73
+ nodeData: {
74
+ type: 'item'
75
+ }
76
+ };
77
+ }
78
+
79
+ function getMapReduceChainsForActionableProposalGroups(proposalGroups, stakeholder) {
80
+ return proposalGroups.map(([label,, queryGetter]) => {
81
+ const query = queryGetter(stakeholder);
82
+ const predicateFunc = `
83
+ const objPath = key, obj = value;
84
+ return ((${_queries.CR_BASE_QUERY}) && (${query}));
85
+ `;
86
+ const mapFunc = `emit(value);`;
87
+ return {
88
+ [label]: {
89
+ mapFunc,
90
+ predicateFunc
91
+ }
92
+ };
93
+ }).reduce((prev, curr) => ({ ...prev,
94
+ ...curr
95
+ }), {});
96
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeNodes.js","sourceRoot":"","sources":["../../../src/proposals/actionableGroups/treeNodes.tsx"],"names":[],"mappings":"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","sourcesContent":["/** @jsx jsx */\n/** @jsxFrag React.Fragment */\n\n/**\n * Tools for rendering proposal groups as tree nodes.\n * Each proposal group is top-level node, with proposals as nested nodes.\n */\n\n//import React, { useContext, useMemo } from 'react';\nimport { jsx } from '@emotion/react';\n\nimport { Tag } from '@blueprintjs/core';\nimport type { IconName, TreeNodeInfo } from '@blueprintjs/core';\nimport type { RegisterStakeholder } from '../../types';\nimport type { SomeCR as CR } from '../../types/cr';\nimport type { ActionableProposalGroup } from './types';\nimport { CR_BASE_QUERY } from './queries';\n\n\nexport type ActionableProposalTreeNode = TreeNodeInfo<{ type: 'group' | 'item' }>;\n\n\ninterface ActionableProposalGroupResult {\n groupLabel: string\n proposals: CR[] | undefined\n}\nexport function getActionableProposalGroupsAsTreeNodes(\n groups: readonly ActionableProposalGroupResult[],\n opts?: {\n expandedGroupLabels?: Set<string>\n selectedGroup?: string\n selectedCRID?: string\n activeCRID?: string\n },\n): ActionableProposalTreeNode[] {\n return groups.\n //filter(({ proposals }) => proposals && proposals.length > 0).\n map(({ groupLabel, proposals }) => {\n const hasProposals = proposals && proposals.length > 0;\n const hasActiveProposal = hasProposals\n && opts?.activeCRID && proposals.find(p => p.id === opts.activeCRID);\n const hasSelectedProposal = hasProposals\n && opts?.selectedCRID && proposals.find(p => p.id === opts.selectedCRID);\n const isExpanded =\n groups.length === 1\n || opts?.expandedGroupLabels?.has(groupLabel)\n || hasSelectedProposal\n ? true\n : false;\n\n return {\n id: groupLabel,\n label: groupLabel,\n hasCaret: true,\n secondaryLabel:\n hasActiveProposal && !isExpanded\n ? activeCRMarker\n : <Tag\n minimal={!hasProposals}\n intent={hasProposals ? 'primary' : undefined}>\n {hasProposals ? proposals.length : 0}\n </Tag>,\n icon: isExpanded\n ? 'folder-open'\n : 'folder-close' as IconName,\n isExpanded,\n isSelected: groupLabel === opts?.selectedGroup,\n nodeData: { type: 'group' },\n childNodes: hasProposals && isExpanded\n ? proposals.map(p => getActionableProposalTreeNode(p, {\n isSelected: p.id === opts?.selectedCRID,\n isActive: p.id === opts?.activeCRID,\n }))\n : [],\n };\n });\n}\n\nconst activeCRMarker = <Tag intent='danger'>active</Tag>;\n\nfunction getActionableProposalTreeNode(\n proposal: CR,\n opts?: { isSelected?: boolean, isActive?: boolean },\n): ActionableProposalTreeNode {\n return {\n id: proposal.id,\n label: <span title={`Double-click the proposal to activate: “${proposal.justification}”`}>\n {proposal.justification}\n </span>,\n isSelected: opts?.isSelected ?? false,\n icon: 'lightbulb',\n secondaryLabel: opts?.isActive ? activeCRMarker : undefined,\n nodeData: { type: 'item' },\n };\n}\n\n\nexport function getMapReduceChainsForActionableProposalGroups(\n proposalGroups: readonly ActionableProposalGroup[],\n stakeholder: RegisterStakeholder,\n) {\n return proposalGroups.map(([label, , queryGetter]) => {\n const query = queryGetter(stakeholder);\n const predicateFunc = `\n const objPath = key, obj = value;\n return ((${CR_BASE_QUERY}) && (${query}));\n `;\n const mapFunc = `emit(value);`;\n return { [label]: { mapFunc, predicateFunc } };\n }).reduce((prev, curr) => ({ ...prev, ...curr }), {});\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { RegisterStakeholder, StakeholderRoleType } from '../../types';
2
+ export declare type ActionableProposalGroup = readonly [
3
+ label: string,
4
+ roles: Set<StakeholderRoleType>,
5
+ queryGetter: (stakeholder?: RegisterStakeholder) => string
6
+ ];
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/proposals/actionableGroups/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RegisterStakeholder, StakeholderRoleType } from '../../types';\n\n\nexport type ActionableProposalGroup = readonly [\n label: string,\n roles: Set<StakeholderRoleType>,\n queryGetter: (stakeholder?: RegisterStakeholder) => string,\n];\n"]}
package/types/cr.d.ts CHANGED
@@ -151,6 +151,7 @@ export interface RegisterManagerInput {
151
151
  export declare function hasRegisterManagerInput(val: any): val is RegisterManagerInput;
152
152
  export interface ControlBodyInput {
153
153
  controlBodyNotes: string;
154
+ controlBodyDecisionEvent: string;
154
155
  }
155
156
  export declare function hasControlBodyInput(val: any): val is ControlBodyInput;
156
157
  export interface AppealRequest {
package/types/cr.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cr.js","sourceRoot":"","sources":["../../src/types/cr.ts"],"names":[],"mappings":"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","sourcesContent":["/** Change request types, states and state transitions. */\n\nimport type React from 'react';\nimport type { DatasetContext } from '@riboseinc/paneron-extension-kit/types/renderer';\nimport type { ProposalSet } from './proposal';\nimport type { RegisterStakeholder } from './stakeholder';\nimport type { RegisterItem } from './item';\n\n\n\nexport function isSubmittedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return (\n //isSubmitter(stakeholder) &&\n stakeholder.gitServerUsername === cr.submittingStakeholderGitServerUsername);\n}\n\n\ntype ItemDataset = Record<string, RegisterItem<any> | null>;\n\n\n// =====================\n// Change request states\n// =====================\n\n/** Used in place of enum for convenience. */\nexport const State = {\n DRAFT: 'draft',\n PROPOSED: 'proposed',\n SUBMITTED_FOR_CONTROL_BODY_REVIEW: 'pending-control-body-review',\n RETURNED_FOR_CLARIFICATION: 'returned-for-clarification',\n WITHDRAWN: 'withdrawn',\n ACCEPTED: 'accepted',\n REJECTED: 'rejected',\n APPEALED: 'rejection-appealed-to-owner',\n ACCEPTED_ON_APPEAL: 'accepted-on-appeal',\n REJECTION_UPHELD_ON_APPEAL: 'rejection-upheld-on-appeal',\n APPEAL_WITHDRAWN: 'appeal-withdrawn',\n} as const;\n\nexport type StateType = typeof State[keyof typeof State];\n\nexport function isState(val: string): val is StateType {\n return Object.values(State).indexOf(val as StateType) >= 0;\n}\n\n/** A subset of `State` that represents editable states. */\nexport const EditableState = [\n State.DRAFT,\n State.RETURNED_FOR_CLARIFICATION,\n] as const;\n\nexport type EditableStateType = StateType & typeof EditableState[number];\n\nexport function isEditableState(state: StateType): state is EditableStateType {\n return EditableState.indexOf(state as EditableStateType) >= 0;\n}\n\n\n\n// ======================\n// Change request classes\n// ======================\n\n/**\n * Base change request type.\n *\n * Note that e.g. type Base<typeof State.DRAFT> does not equal to Drafted\n * because Drafted includes additional information (namely, SubmitterInput).\n *\n * If the state of a CR matters, this type should not be used directly\n * and concrete types should be used instead.\n */\nexport interface Base<S extends StateType = StateType>\n{\n id: string;\n // decision: typeof Decision[keyof typeof Decision]\n // disposition?: typeof Disposition[keyof typeof Disposition]\n state: S;\n\n /**\n * Used to match against stakeholders declared in register metadata.\n */\n submittingStakeholderGitServerUsername: string;\n\n items: ProposalSet;\n\n /**\n * Against to which register version changes were proposed.\n */\n registerVersion: string;\n\n /**\n * A link to external discussion.\n */\n externalDiscussionURI?: string;\n\n pastTransitions?: TransitionEntry[];\n}\n\n\nexport interface TransitionEntry {\n /** Verb in past tense. */\n label: string;\n\n timestamp: Date;\n fromState: StateType;\n toState: StateType;\n stakeholder: RegisterStakeholder;\n input: StateInput;\n}\n\n\nexport function isCreatedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return stakeholder.gitServerUsername?.trim() !== '' && stakeholder.gitServerUsername === cr.submittingStakeholderGitServerUsername;\n}\n\n/** Whether given `cr` can be edited (as in, items changed) by specified stakeholder. */\nexport function canBeEditedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return isCreatedBy(stakeholder, cr) && isEditableState(cr.state);\n}\n\n/**\n * Whether given `cr` can be deleted by given stakeholder.\n * Unlike editing, deletion is possible only if there are no items\n * and CR was never proposed.\n */\nexport function canBeDeletedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return (\n isCreatedBy(stakeholder, cr)\n && isDrafted(cr)\n //&& Object.keys(cr.items).length < 1 // Only allow deleting empty CRs\n && !hadBeenProposed(cr) // If it had been proposed, it should be withdrawn instead.\n );\n}\n\n\n/** Proposal structure for single-file proposal import format. */\nexport interface ImportableCR {\n /** Proposal data. */\n proposalDraft: Drafted,\n /** Register item data for additions & clarifications. */\n itemPayloads: ItemDataset,\n // TODO: Rename ImportableCR.itemPayloads to newItemData\n}\nexport function isImportableCR(val: any): val is ImportableCR {\n // TODO: More complete check\n return (\n val.proposalDraft.id\n && isDrafted(val.proposalDraft as Base)\n && Object.keys(val.itemPayloads).length > 0);\n}\n\n\n/**\n * A change request in any state.\n * Contains a superset of all possible properties, but all optional.\n * XXX: ^^^ This is a lie. Should be changed from | to & with Partial<>?\n */\nexport type SomeCR = \n | Drafted\n | Proposed\n | Withdrawn\n | ReturnedForClarificationByManager\n | SubmittedForControlBodyReview\n | ReturnedForClarificationByControlBody\n | Accepted\n | Rejected\n | RejectionUpheld\n | AcceptedOnAppeal\n | RejectedWithAppealWithdrawn;\n\nexport type Withdrawable =\n | Proposed\n | SubmittedForControlBodyReview\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type Proposable =\n | Drafted\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type SomeEditable =\n | Drafted\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type Disposed =\n | Withdrawn\n | Accepted\n | Rejected\n | AcceptedOnAppeal\n | RejectionUpheld;\n\n\n// More specific change request types.\n// TODO: Refactor to avoid confusiong between current state e.g. Proposed)\n// and type (Proposed, to which all inheriting classes also conform)\n\nexport interface Drafted extends\n SubmitterInput,\n Base<typeof State.DRAFT> { timeStarted: Date, timeEdited: Date }\nexport function isDrafted(cr: Base): cr is Drafted {\n return isInState(cr, State.DRAFT);\n}\n\nexport interface Proposed extends\n Omit<Drafted, 'state'>,\n Base<typeof State.PROPOSED> { timeProposed: Date }\nexport function isProposed(cr: Base): cr is Proposed {\n return isInState(cr, State.PROPOSED);\n}\n\nexport interface Withdrawn extends\n Omit<Withdrawable, 'state'>,\n Base<typeof State.WITHDRAWN> { timeDisposed: Date }\nexport function isWithdrawn(cr: Base): cr is Withdrawn {\n return isInState(cr, State.WITHDRAWN);\n}\n\n/** CR was proposed at least once. */\nexport function hadBeenProposed(cr: Base): cr is Base & { timeProposed: Date } {\n return cr && cr.hasOwnProperty('timeProposed') && !!(cr as Proposed).timeProposed;\n}\nexport function isDisposed(cr: Base): cr is Base & { timeDisposed: Date } {\n return cr && cr.hasOwnProperty('timeDisposed') && !!(cr as Disposed).timeDisposed;\n //return [\n // State.WITHDRAWN,\n // State.ACCEPTED,\n // State.REJECTED,\n // State.REJECTION_UPHELD_ON_APPEAL,\n // State.ACCEPTED_ON_APPEAL,\n //].some(s => cr.state === s);\n}\n\nexport interface SubmittedForControlBodyReview extends\n Omit<Proposed, 'state'>,\n RegisterManagerInput,\n Base<typeof State.SUBMITTED_FOR_CONTROL_BODY_REVIEW> {}\n\nexport function isSubmittedForControlBodyReview(cr: Base): cr is SubmittedForControlBodyReview {\n return isInState(cr, State.SUBMITTED_FOR_CONTROL_BODY_REVIEW)\n}\n\nexport interface ReturnedForClarificationByManager extends\n Omit<Proposed, 'state'>,\n RegisterManagerInput,\n Base<typeof State.RETURNED_FOR_CLARIFICATION> {}\n\nexport interface ReturnedForClarificationByControlBody extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.RETURNED_FOR_CLARIFICATION> {}\n\nexport function isReturnedForClarification(cr: Base): cr is (ReturnedForClarificationByManager | ReturnedForClarificationByControlBody) {\n return isInState(cr, State.RETURNED_FOR_CLARIFICATION)\n}\n\nexport interface Accepted extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.ACCEPTED> { timeDisposed: Date }\nexport function isAccepted(cr: Base): cr is Accepted {\n return isInState(cr, State.ACCEPTED);\n}\n\nexport interface Rejected extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.REJECTED> { timeDisposed: Date }\nexport function isRejected(cr: Base): cr is Rejected {\n return isInState(cr, State.REJECTED);\n}\n\nexport interface Appealed extends\n Omit<Rejected, 'state' | 'timeDisposed'>,\n AppealRequest,\n Base<typeof State.APPEALED> { timeDisposed: undefined }\nexport function isAppealed(cr: Base): cr is Appealed {\n return isInState(cr, State.APPEALED);\n}\n\nexport interface RejectionUpheld extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n RegisterOwnerInput,\n Base<typeof State.REJECTION_UPHELD_ON_APPEAL> { timeDisposed: Date }\nexport function isRejectedOnAppeal(cr: Base): cr is RejectionUpheld {\n return isInState(cr, State.REJECTION_UPHELD_ON_APPEAL);\n}\n\nexport interface AcceptedOnAppeal extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n RegisterOwnerInput,\n Base<typeof State.ACCEPTED_ON_APPEAL> { timeDisposed: Date }\nexport function isAcceptedOnAppeal(cr: Base): cr is AcceptedOnAppeal {\n return isInState(cr, State.ACCEPTED_ON_APPEAL);\n}\n\nexport interface RejectedWithAppealWithdrawn extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n Base<typeof State.APPEAL_WITHDRAWN> { timeDisposed: Date }\nexport function isRejectedWithAppealWithdrawn(cr: Base): cr is RejectedWithAppealWithdrawn {\n return isInState(cr, State.APPEAL_WITHDRAWN);\n}\n\n\n\n// Input required when transitioning to different states\n\nexport interface SubmitterInput {\n justification: string;\n}\nexport function hasSubmitterInput(val: any): val is SubmitterInput {\n return val.hasOwnProperty('justification') && typeof val.justification === 'string';\n}\nexport interface RegisterManagerInput {\n registerManagerNotes: string;\n}\nexport function hasRegisterManagerInput(val: any): val is RegisterManagerInput {\n return val.hasOwnProperty('registerManagerNotes') && typeof val.registerManagerNotes === 'string';\n}\nexport interface ControlBodyInput {\n controlBodyNotes: string;\n}\nexport function hasControlBodyInput(val: any): val is ControlBodyInput {\n return (\n val.hasOwnProperty('controlBodyNotes') && typeof val.controlBodyNotes === 'string' &&\n val.hasOwnProperty('controlBodyDecisionEvent') && typeof val.controlBodyDecisionEvent === 'string');\n}\nexport interface AppealRequest {\n appealReason: string;\n}\nexport function hasAppealRequest(val: any): val is AppealRequest {\n return val.hasOwnProperty('appealReason') && typeof val.appealReason === 'string';\n}\nexport interface RegisterOwnerInput {\n registerOwnerNotes: string;\n}\nexport function hasRegisterOwnerInput(val: any): val is RegisterOwnerInput {\n return val.hasOwnProperty('registerOwnerNotes') && typeof val.registerOwnerNotes === 'string';\n}\n\nexport type StateInput =\n | SubmitterInput\n | RegisterManagerInput\n | ControlBodyInput\n | AppealRequest\n | RegisterOwnerInput;\n\n\n/** \n * CR type guard helper.\n * Normally you would not use it directly and instead use\n * more specific is[Type]() helper from this module.\n *\n * Checks CR type using the `state` property.\n * Does not validate other properties.\n *\n * Usage:\n *\n * @example\n * ```ts\n * let someCR;\n * if (isInState<Drafted>(someCR, State.DRAFT)) {\n * // Can assume someCR is Drafted\n * }\n * ```\n *\n * It’ll try to tell you if you mismatch those.\n *\n * @example\n * Will not compile:\n * ```ts\n * let someCR;\n * if (isInState<Drafted>(someCR, State.PROPOSED)) {\n * // Compile error\n * // because State.PROPOSED is not a possible value of Drafted[\"state\"]\n * }\n * ```\n *\n * @example\n * Incorrect usage (do not do this):\n * ```ts\n * let someCR;\n * if (isInState(someCR, State.DRAFT)) {\n * // Can NOT assume someCR is Drafted\n * // The compiler must know the expected concrete CR type\n * }\n * ```\n */\nfunction isInState<CR extends Base>(cr: Base, s: CR[\"state\"]): cr is CR {\n return cr.state === s;\n}\n\n\n\n\n// ===========\n// Transitions\n// ===========\n\n/**\n * A function that transitions CR1 to CR2.\n *\n * The function is declared to return the object\n * without the `state` field, it is set\n * by common wrapper function to reduce duplication.\n */\nexport type Transition<\n /** From CR of this subtype */\n CR1 extends Base,\n /** To CR of this subtype */\n CR2 extends Base,\n /** Using this extra information */\n P extends Record<string, any> | null = null,\n> = (cr: CR1, payload: P) => Omit<CR2, 'state'>;\n\n\nexport type AlterApprovedCR = (\n crID: string,\n proposals: ProposalSet,\n origItemData: ItemDataset,\n newItemData: ItemDataset,\n opts: Pick<DatasetContext, 'getMapReducedData'>,\n) => Promise<{\n proposals: ProposalSet,\n origItemData: ItemDataset,\n newItemData: ItemDataset,\n}>\n\n\n/**\n * Describes a transition.\n *\n * @typeParam CR1: Change request source state type\n * @typeParam CR2: Change request target state type\n * @typeParam P: Extra input needed to transition, if any\n */\nexport interface TransitionConfig<CR1 extends Base, CR2 extends Base, P extends Record<string, any> | null = null> {\n /**\n * Function that implements the transition.\n * Takes a CR in the original state and returns CR in the new state.\n * Additionally, takes appropriate payload, if any, for the transition\n * (e.g., register manager or control body notes).\n *\n * For function implementor:\n *\n * - Function MUST NOT modify CR in place.\n * - Function should throw if submitted payload does not conform to requirements.\n */\n func: Transition<CR1, CR2, P>;\n\n targetState: CR2[\"state\"];\n\n /** Title. Use verb. */\n title: string;\n\n hint?: string | JSX.Element;\n\n /** Widget that can be used to view or enter extra input. */\n Widget: P extends null ? null : React.FC<{ value: P, onChange?: (userInput: P) => void }>;\n\n /**\n * Function that returns true\n * if given stakeholder can perform this transition on given CR.\n */\n canBeTransitionedBy: (stakeholder: RegisterStakeholder, cr: CR1) => boolean;\n}\n\n\n// type TransitionSpec = {\n// [S1 in StateType]?: {\n// [S2 in StateType]?: Transition<Base<S1>, Base<S2>, Record<string, any>>\n// }\n// }\n\n\n/**\n * Source of truth for available transitions.\n * When updating change request business logic,\n * this is the type that should be modified.\n *\n * It will cause compile errors until transition implementation\n * is updated correspondingly.\n */\nexport type Transitions = {\n [State.DRAFT]: {\n // [State.DRAFT]:\n // TransitionConfig<Drafted, Drafted, SubmitterInput>;\n [State.WITHDRAWN]:\n TransitionConfig<Proposed, Withdrawn>;\n [State.PROPOSED]:\n TransitionConfig<Drafted, Proposed, SubmitterInput>;\n };\n [State.PROPOSED]: {\n [State.WITHDRAWN]:\n TransitionConfig<Proposed, Withdrawn>;\n [State.SUBMITTED_FOR_CONTROL_BODY_REVIEW]:\n TransitionConfig<Proposed, SubmittedForControlBodyReview, RegisterManagerInput>;\n [State.RETURNED_FOR_CLARIFICATION]:\n TransitionConfig<Proposed, ReturnedForClarificationByManager, RegisterManagerInput>;\n };\n [State.SUBMITTED_FOR_CONTROL_BODY_REVIEW]: {\n [State.WITHDRAWN]:\n TransitionConfig<SubmittedForControlBodyReview, Withdrawn>;\n [State.RETURNED_FOR_CLARIFICATION]:\n TransitionConfig<SubmittedForControlBodyReview, ReturnedForClarificationByControlBody, ControlBodyInput>;\n [State.REJECTED]:\n TransitionConfig<SubmittedForControlBodyReview, Rejected, ControlBodyInput>;\n [State.ACCEPTED]:\n TransitionConfig<SubmittedForControlBodyReview, Accepted, ControlBodyInput>;\n };\n [State.RETURNED_FOR_CLARIFICATION]: {\n [State.PROPOSED]:\n TransitionConfig<ReturnedForClarificationByManager | ReturnedForClarificationByControlBody, Proposed, SubmitterInput>;\n [State.WITHDRAWN]:\n TransitionConfig<ReturnedForClarificationByManager | ReturnedForClarificationByControlBody, Withdrawn>;\n };\n [State.REJECTED]: {\n [State.APPEALED]:\n TransitionConfig<Rejected, Appealed, AppealRequest>;\n };\n [State.APPEALED]: {\n [State.APPEAL_WITHDRAWN]:\n TransitionConfig<Appealed, RejectedWithAppealWithdrawn>;\n [State.ACCEPTED_ON_APPEAL]:\n TransitionConfig<Appealed, AcceptedOnAppeal, RegisterOwnerInput>;\n [State.REJECTION_UPHELD_ON_APPEAL]:\n TransitionConfig<Appealed, RejectionUpheld, RegisterOwnerInput>;\n };\n}\n"]}
1
+ {"version":3,"file":"cr.js","sourceRoot":"","sources":["../../src/types/cr.ts"],"names":[],"mappings":"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","sourcesContent":["/** Change request types, states and state transitions. */\n\nimport type React from 'react';\nimport type { DatasetContext } from '@riboseinc/paneron-extension-kit/types/renderer';\nimport type { ProposalSet } from './proposal';\nimport type { RegisterStakeholder } from './stakeholder';\nimport type { RegisterItem } from './item';\n\n\n\nexport function isSubmittedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return (\n //isSubmitter(stakeholder) &&\n stakeholder.gitServerUsername === cr.submittingStakeholderGitServerUsername);\n}\n\n\ntype ItemDataset = Record<string, RegisterItem<any> | null>;\n\n\n// =====================\n// Change request states\n// =====================\n\n/** Used in place of enum for convenience. */\nexport const State = {\n DRAFT: 'draft',\n PROPOSED: 'proposed',\n SUBMITTED_FOR_CONTROL_BODY_REVIEW: 'pending-control-body-review',\n RETURNED_FOR_CLARIFICATION: 'returned-for-clarification',\n WITHDRAWN: 'withdrawn',\n ACCEPTED: 'accepted',\n REJECTED: 'rejected',\n APPEALED: 'rejection-appealed-to-owner',\n ACCEPTED_ON_APPEAL: 'accepted-on-appeal',\n REJECTION_UPHELD_ON_APPEAL: 'rejection-upheld-on-appeal',\n APPEAL_WITHDRAWN: 'appeal-withdrawn',\n} as const;\n\nexport type StateType = typeof State[keyof typeof State];\n\nexport function isState(val: string): val is StateType {\n return Object.values(State).indexOf(val as StateType) >= 0;\n}\n\n/** A subset of `State` that represents editable states. */\nexport const EditableState = [\n State.DRAFT,\n State.RETURNED_FOR_CLARIFICATION,\n] as const;\n\nexport type EditableStateType = StateType & typeof EditableState[number];\n\nexport function isEditableState(state: StateType): state is EditableStateType {\n return EditableState.indexOf(state as EditableStateType) >= 0;\n}\n\n\n\n// ======================\n// Change request classes\n// ======================\n\n/**\n * Base change request type.\n *\n * Note that e.g. type Base<typeof State.DRAFT> does not equal to Drafted\n * because Drafted includes additional information (namely, SubmitterInput).\n *\n * If the state of a CR matters, this type should not be used directly\n * and concrete types should be used instead.\n */\nexport interface Base<S extends StateType = StateType>\n{\n id: string;\n // decision: typeof Decision[keyof typeof Decision]\n // disposition?: typeof Disposition[keyof typeof Disposition]\n state: S;\n\n /**\n * Used to match against stakeholders declared in register metadata.\n */\n submittingStakeholderGitServerUsername: string;\n\n items: ProposalSet;\n\n /**\n * Against to which register version changes were proposed.\n */\n registerVersion: string;\n\n /**\n * A link to external discussion.\n */\n externalDiscussionURI?: string;\n\n pastTransitions?: TransitionEntry[];\n}\n\n\nexport interface TransitionEntry {\n /** Verb in past tense. */\n label: string;\n\n timestamp: Date;\n fromState: StateType;\n toState: StateType;\n stakeholder: RegisterStakeholder;\n input: StateInput;\n}\n\n\nexport function isCreatedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return stakeholder.gitServerUsername?.trim() !== '' && stakeholder.gitServerUsername === cr.submittingStakeholderGitServerUsername;\n}\n\n/** Whether given `cr` can be edited (as in, items changed) by specified stakeholder. */\nexport function canBeEditedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return isCreatedBy(stakeholder, cr) && isEditableState(cr.state);\n}\n\n/**\n * Whether given `cr` can be deleted by given stakeholder.\n * Unlike editing, deletion is possible only if there are no items\n * and CR was never proposed.\n */\nexport function canBeDeletedBy(stakeholder: RegisterStakeholder, cr: Base): boolean {\n return (\n isCreatedBy(stakeholder, cr)\n && isDrafted(cr)\n //&& Object.keys(cr.items).length < 1 // Only allow deleting empty CRs\n && !hadBeenProposed(cr) // If it had been proposed, it should be withdrawn instead.\n );\n}\n\n\n/** Proposal structure for single-file proposal import format. */\nexport interface ImportableCR {\n /** Proposal data. */\n proposalDraft: Drafted,\n /** Register item data for additions & clarifications. */\n itemPayloads: ItemDataset,\n // TODO: Rename ImportableCR.itemPayloads to newItemData\n}\nexport function isImportableCR(val: any): val is ImportableCR {\n // TODO: More complete check\n return (\n val.proposalDraft.id\n && isDrafted(val.proposalDraft as Base)\n && Object.keys(val.itemPayloads).length > 0);\n}\n\n\n/**\n * A change request in any state.\n * Contains a superset of all possible properties, but all optional.\n * XXX: ^^^ This is a lie. Should be changed from | to & with Partial<>?\n */\nexport type SomeCR = \n | Drafted\n | Proposed\n | Withdrawn\n | ReturnedForClarificationByManager\n | SubmittedForControlBodyReview\n | ReturnedForClarificationByControlBody\n | Accepted\n | Rejected\n | RejectionUpheld\n | AcceptedOnAppeal\n | RejectedWithAppealWithdrawn;\n\nexport type Withdrawable =\n | Proposed\n | SubmittedForControlBodyReview\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type Proposable =\n | Drafted\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type SomeEditable =\n | Drafted\n | ReturnedForClarificationByManager\n | ReturnedForClarificationByControlBody;\n\nexport type Disposed =\n | Withdrawn\n | Accepted\n | Rejected\n | AcceptedOnAppeal\n | RejectionUpheld;\n\n\n// More specific change request types.\n// TODO: Refactor to avoid confusiong between current state e.g. Proposed)\n// and type (Proposed, to which all inheriting classes also conform)\n\nexport interface Drafted extends\n SubmitterInput,\n Base<typeof State.DRAFT> { timeStarted: Date, timeEdited: Date }\nexport function isDrafted(cr: Base): cr is Drafted {\n return isInState(cr, State.DRAFT);\n}\n\nexport interface Proposed extends\n Omit<Drafted, 'state'>,\n Base<typeof State.PROPOSED> { timeProposed: Date }\nexport function isProposed(cr: Base): cr is Proposed {\n return isInState(cr, State.PROPOSED);\n}\n\nexport interface Withdrawn extends\n Omit<Withdrawable, 'state'>,\n Base<typeof State.WITHDRAWN> { timeDisposed: Date }\nexport function isWithdrawn(cr: Base): cr is Withdrawn {\n return isInState(cr, State.WITHDRAWN);\n}\n\n/** CR was proposed at least once. */\nexport function hadBeenProposed(cr: Base): cr is Base & { timeProposed: Date } {\n return cr && cr.hasOwnProperty('timeProposed') && !!(cr as Proposed).timeProposed;\n}\nexport function isDisposed(cr: Base): cr is Base & { timeDisposed: Date } {\n return cr && cr.hasOwnProperty('timeDisposed') && !!(cr as Disposed).timeDisposed;\n //return [\n // State.WITHDRAWN,\n // State.ACCEPTED,\n // State.REJECTED,\n // State.REJECTION_UPHELD_ON_APPEAL,\n // State.ACCEPTED_ON_APPEAL,\n //].some(s => cr.state === s);\n}\n\nexport interface SubmittedForControlBodyReview extends\n Omit<Proposed, 'state'>,\n RegisterManagerInput,\n Base<typeof State.SUBMITTED_FOR_CONTROL_BODY_REVIEW> {}\n\nexport function isSubmittedForControlBodyReview(cr: Base): cr is SubmittedForControlBodyReview {\n return isInState(cr, State.SUBMITTED_FOR_CONTROL_BODY_REVIEW)\n}\n\nexport interface ReturnedForClarificationByManager extends\n Omit<Proposed, 'state'>,\n RegisterManagerInput,\n Base<typeof State.RETURNED_FOR_CLARIFICATION> {}\n\nexport interface ReturnedForClarificationByControlBody extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.RETURNED_FOR_CLARIFICATION> {}\n\nexport function isReturnedForClarification(cr: Base): cr is (ReturnedForClarificationByManager | ReturnedForClarificationByControlBody) {\n return isInState(cr, State.RETURNED_FOR_CLARIFICATION)\n}\n\nexport interface Accepted extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.ACCEPTED> { timeDisposed: Date }\nexport function isAccepted(cr: Base): cr is Accepted {\n return isInState(cr, State.ACCEPTED);\n}\n\nexport interface Rejected extends\n Omit<SubmittedForControlBodyReview, 'state'>,\n ControlBodyInput,\n Base<typeof State.REJECTED> { timeDisposed: Date }\nexport function isRejected(cr: Base): cr is Rejected {\n return isInState(cr, State.REJECTED);\n}\n\nexport interface Appealed extends\n Omit<Rejected, 'state' | 'timeDisposed'>,\n AppealRequest,\n Base<typeof State.APPEALED> { timeDisposed: undefined }\nexport function isAppealed(cr: Base): cr is Appealed {\n return isInState(cr, State.APPEALED);\n}\n\nexport interface RejectionUpheld extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n RegisterOwnerInput,\n Base<typeof State.REJECTION_UPHELD_ON_APPEAL> { timeDisposed: Date }\nexport function isRejectedOnAppeal(cr: Base): cr is RejectionUpheld {\n return isInState(cr, State.REJECTION_UPHELD_ON_APPEAL);\n}\n\nexport interface AcceptedOnAppeal extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n RegisterOwnerInput,\n Base<typeof State.ACCEPTED_ON_APPEAL> { timeDisposed: Date }\nexport function isAcceptedOnAppeal(cr: Base): cr is AcceptedOnAppeal {\n return isInState(cr, State.ACCEPTED_ON_APPEAL);\n}\n\nexport interface RejectedWithAppealWithdrawn extends\n Omit<Appealed, 'state' | 'timeDisposed'>,\n Base<typeof State.APPEAL_WITHDRAWN> { timeDisposed: Date }\nexport function isRejectedWithAppealWithdrawn(cr: Base): cr is RejectedWithAppealWithdrawn {\n return isInState(cr, State.APPEAL_WITHDRAWN);\n}\n\n\n\n// Input required when transitioning to different states\n\nexport interface SubmitterInput {\n justification: string;\n}\nexport function hasSubmitterInput(val: any): val is SubmitterInput {\n return val.hasOwnProperty('justification') && typeof val.justification === 'string';\n}\nexport interface RegisterManagerInput {\n registerManagerNotes: string;\n}\nexport function hasRegisterManagerInput(val: any): val is RegisterManagerInput {\n return val.hasOwnProperty('registerManagerNotes') && typeof val.registerManagerNotes === 'string';\n}\nexport interface ControlBodyInput {\n controlBodyNotes: string;\n controlBodyDecisionEvent: string;\n}\nexport function hasControlBodyInput(val: any): val is ControlBodyInput {\n return (\n val.hasOwnProperty('controlBodyNotes') && typeof val.controlBodyNotes === 'string' &&\n val.hasOwnProperty('controlBodyDecisionEvent') && typeof val.controlBodyDecisionEvent === 'string');\n}\nexport interface AppealRequest {\n appealReason: string;\n}\nexport function hasAppealRequest(val: any): val is AppealRequest {\n return val.hasOwnProperty('appealReason') && typeof val.appealReason === 'string';\n}\nexport interface RegisterOwnerInput {\n registerOwnerNotes: string;\n}\nexport function hasRegisterOwnerInput(val: any): val is RegisterOwnerInput {\n return val.hasOwnProperty('registerOwnerNotes') && typeof val.registerOwnerNotes === 'string';\n}\n\nexport type StateInput =\n | SubmitterInput\n | RegisterManagerInput\n | ControlBodyInput\n | AppealRequest\n | RegisterOwnerInput;\n\n\n/** \n * CR type guard helper.\n * Normally you would not use it directly and instead use\n * more specific is[Type]() helper from this module.\n *\n * Checks CR type using the `state` property.\n * Does not validate other properties.\n *\n * Usage:\n *\n * @example\n * ```ts\n * let someCR;\n * if (isInState<Drafted>(someCR, State.DRAFT)) {\n * // Can assume someCR is Drafted\n * }\n * ```\n *\n * It’ll try to tell you if you mismatch those.\n *\n * @example\n * Will not compile:\n * ```ts\n * let someCR;\n * if (isInState<Drafted>(someCR, State.PROPOSED)) {\n * // Compile error\n * // because State.PROPOSED is not a possible value of Drafted[\"state\"]\n * }\n * ```\n *\n * @example\n * Incorrect usage (do not do this):\n * ```ts\n * let someCR;\n * if (isInState(someCR, State.DRAFT)) {\n * // Can NOT assume someCR is Drafted\n * // The compiler must know the expected concrete CR type\n * }\n * ```\n */\nfunction isInState<CR extends Base>(cr: Base, s: CR[\"state\"]): cr is CR {\n return cr.state === s;\n}\n\n\n\n\n// ===========\n// Transitions\n// ===========\n\n/**\n * A function that transitions CR1 to CR2.\n *\n * The function is declared to return the object\n * without the `state` field, it is set\n * by common wrapper function to reduce duplication.\n */\nexport type Transition<\n /** From CR of this subtype */\n CR1 extends Base,\n /** To CR of this subtype */\n CR2 extends Base,\n /** Using this extra information */\n P extends Record<string, any> | null = null,\n> = (cr: CR1, payload: P) => Omit<CR2, 'state'>;\n\n\nexport type AlterApprovedCR = (\n crID: string,\n proposals: ProposalSet,\n origItemData: ItemDataset,\n newItemData: ItemDataset,\n opts: Pick<DatasetContext, 'getMapReducedData'>,\n) => Promise<{\n proposals: ProposalSet,\n origItemData: ItemDataset,\n newItemData: ItemDataset,\n}>\n\n\n/**\n * Describes a transition.\n *\n * @typeParam CR1: Change request source state type\n * @typeParam CR2: Change request target state type\n * @typeParam P: Extra input needed to transition, if any\n */\nexport interface TransitionConfig<CR1 extends Base, CR2 extends Base, P extends Record<string, any> | null = null> {\n /**\n * Function that implements the transition.\n * Takes a CR in the original state and returns CR in the new state.\n * Additionally, takes appropriate payload, if any, for the transition\n * (e.g., register manager or control body notes).\n *\n * For function implementor:\n *\n * - Function MUST NOT modify CR in place.\n * - Function should throw if submitted payload does not conform to requirements.\n */\n func: Transition<CR1, CR2, P>;\n\n targetState: CR2[\"state\"];\n\n /** Title. Use verb. */\n title: string;\n\n hint?: string | JSX.Element;\n\n /** Widget that can be used to view or enter extra input. */\n Widget: P extends null ? null : React.FC<{ value: P, onChange?: (userInput: P) => void }>;\n\n /**\n * Function that returns true\n * if given stakeholder can perform this transition on given CR.\n */\n canBeTransitionedBy: (stakeholder: RegisterStakeholder, cr: CR1) => boolean;\n}\n\n\n// type TransitionSpec = {\n// [S1 in StateType]?: {\n// [S2 in StateType]?: Transition<Base<S1>, Base<S2>, Record<string, any>>\n// }\n// }\n\n\n/**\n * Source of truth for available transitions.\n * When updating change request business logic,\n * this is the type that should be modified.\n *\n * It will cause compile errors until transition implementation\n * is updated correspondingly.\n */\nexport type Transitions = {\n [State.DRAFT]: {\n // [State.DRAFT]:\n // TransitionConfig<Drafted, Drafted, SubmitterInput>;\n [State.WITHDRAWN]:\n TransitionConfig<Proposed, Withdrawn>;\n [State.PROPOSED]:\n TransitionConfig<Drafted, Proposed, SubmitterInput>;\n };\n [State.PROPOSED]: {\n [State.WITHDRAWN]:\n TransitionConfig<Proposed, Withdrawn>;\n [State.SUBMITTED_FOR_CONTROL_BODY_REVIEW]:\n TransitionConfig<Proposed, SubmittedForControlBodyReview, RegisterManagerInput>;\n [State.RETURNED_FOR_CLARIFICATION]:\n TransitionConfig<Proposed, ReturnedForClarificationByManager, RegisterManagerInput>;\n };\n [State.SUBMITTED_FOR_CONTROL_BODY_REVIEW]: {\n [State.WITHDRAWN]:\n TransitionConfig<SubmittedForControlBodyReview, Withdrawn>;\n [State.RETURNED_FOR_CLARIFICATION]:\n TransitionConfig<SubmittedForControlBodyReview, ReturnedForClarificationByControlBody, ControlBodyInput>;\n [State.REJECTED]:\n TransitionConfig<SubmittedForControlBodyReview, Rejected, ControlBodyInput>;\n [State.ACCEPTED]:\n TransitionConfig<SubmittedForControlBodyReview, Accepted, ControlBodyInput>;\n };\n [State.RETURNED_FOR_CLARIFICATION]: {\n [State.PROPOSED]:\n TransitionConfig<ReturnedForClarificationByManager | ReturnedForClarificationByControlBody, Proposed, SubmitterInput>;\n [State.WITHDRAWN]:\n TransitionConfig<ReturnedForClarificationByManager | ReturnedForClarificationByControlBody, Withdrawn>;\n };\n [State.REJECTED]: {\n [State.APPEALED]:\n TransitionConfig<Rejected, Appealed, AppealRequest>;\n };\n [State.APPEALED]: {\n [State.APPEAL_WITHDRAWN]:\n TransitionConfig<Appealed, RejectedWithAppealWithdrawn>;\n [State.ACCEPTED_ON_APPEAL]:\n TransitionConfig<Appealed, AcceptedOnAppeal, RegisterOwnerInput>;\n [State.REJECTION_UPHELD_ON_APPEAL]:\n TransitionConfig<Appealed, RejectionUpheld, RegisterOwnerInput>;\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { type RegisterStakeholder } from './stakeholder';
1
+ import { type RegisterStakeholder, type Organization } from './stakeholder';
2
2
  import { type Locale } from './util';
3
3
  export interface Register {
4
4
  id?: string;
@@ -9,6 +9,9 @@ export interface Register {
9
9
  alternativeLanguages: Locale[];
10
10
  version?: Version;
11
11
  stakeholders: RegisterStakeholder[];
12
+ organizations: {
13
+ [orgID: string]: Organization;
14
+ };
12
15
  }
13
16
  export declare function isRegisterMetadata(val: any): val is Register;
14
17
  export interface Version {
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/types/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAkBhF,MAAM,UAAU,kBAAkB,CAAC,GAAQ;IACzC,OAAO,CACL,GAAG;QACH,8BAA8B;QAC9B,+BAA+B;QAC/B,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,yCAAyC;QACzC,2CAA2C;QAC3C,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC;QAClC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QAC3B,6BAA6B;QAC7B,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,qBAAqB,CAAC;QAC7C,kCAAkC;QAClC,2EAA2E;QAC3E,iDAAiD;QACjD,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAOD,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;QACxB,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC;QAC/B,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;AAChC,CAAC","sourcesContent":["import { type RegisterStakeholder, isRegisterStakeholder } from './stakeholder';\nimport { type Locale } from './util';\n\n\nexport interface Register {\n // TODO: what is register ID? Perhaps URI is enough?\n id?: string\n name: string\n contentSummary: string\n uniformResourceIdentifier: string\n\n operatingLanguage: Locale\n alternativeLanguages: Locale[]\n\n version?: Version\n stakeholders: RegisterStakeholder[]\n}\n\nexport function isRegisterMetadata(val: any): val is Register {\n return (\n val &&\n // val.hasOwnProperty('id') &&\n //typeof val.id === 'string' &&\n val.hasOwnProperty('name') &&\n typeof val.name === 'string' &&\n //val.hasOwnProperty('contentSummary') &&\n //typeof val.contentSummary === 'string' &&\n val.hasOwnProperty('stakeholders') &&\n val.stakeholders.length > 0 &&\n // Stakeholders must be right\n val.stakeholders.every(isRegisterStakeholder) &&\n // Must have at least an owner? No\n // val.stakeholders.some((s: RegisterStakeholder) => s.role === 'owner') &&\n // Must have a valid version (or no version? hmm)\n (val.version === undefined || isVersion(val.version)));\n}\n\nexport interface Version {\n id: string\n timestamp: Date\n}\n\nexport function isVersion(val: any): val is Version {\n return (\n val &&\n val.hasOwnProperty('id') &&\n val.hasOwnProperty('timestamp') &&\n typeof val.id === 'string');\n}\n"]}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/types/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAsBnG,MAAM,UAAU,kBAAkB,CAAC,GAAQ;IACzC,OAAO,CACL,GAAG;QACH,8BAA8B;QAC9B,+BAA+B;QAC/B,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,yCAAyC;QACzC,2CAA2C;QAC3C,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC;QAClC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QAC3B,6BAA6B;QAC7B,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,qBAAqB,CAAC;QAC7C,kCAAkC;QAClC,2EAA2E;QAC3E,iDAAiD;QACjD,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAOD,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;QACxB,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC;QAC/B,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;AAChC,CAAC","sourcesContent":["import { type RegisterStakeholder, type Organization, isRegisterStakeholder } from './stakeholder';\nimport { type Locale } from './util';\n\n\nexport interface Register {\n // TODO: what is register ID? Perhaps URI is enough?\n id?: string\n name: string\n contentSummary: string\n uniformResourceIdentifier: string\n\n operatingLanguage: Locale\n alternativeLanguages: Locale[]\n\n version?: Version\n stakeholders: RegisterStakeholder[]\n\n organizations: {\n [orgID: string]: Organization\n }\n}\n\nexport function isRegisterMetadata(val: any): val is Register {\n return (\n val &&\n // val.hasOwnProperty('id') &&\n //typeof val.id === 'string' &&\n val.hasOwnProperty('name') &&\n typeof val.name === 'string' &&\n //val.hasOwnProperty('contentSummary') &&\n //typeof val.contentSummary === 'string' &&\n val.hasOwnProperty('stakeholders') &&\n val.stakeholders.length > 0 &&\n // Stakeholders must be right\n val.stakeholders.every(isRegisterStakeholder) &&\n // Must have at least an owner? No\n // val.stakeholders.some((s: RegisterStakeholder) => s.role === 'owner') &&\n // Must have a valid version (or no version? hmm)\n (val.version === undefined || isVersion(val.version)));\n}\n\nexport interface Version {\n id: string\n timestamp: Date\n}\n\nexport function isVersion(val: any): val is Version {\n return (\n val &&\n val.hasOwnProperty('id') &&\n val.hasOwnProperty('timestamp') &&\n typeof val.id === 'string');\n}\n"]}
@@ -2,61 +2,42 @@
2
2
  export declare const StakeholderRole: {
3
3
  readonly Owner: "owner";
4
4
  readonly ControlBody: "control-body";
5
- readonly ControlBodyRevew: "control-body-reviewer";
5
+ readonly ControlBodyReview: "control-body-reviewer";
6
6
  readonly Manager: "manager";
7
7
  readonly Submitter: "submitter";
8
8
  };
9
+ export declare const StakeholderRoleLabels: Record<StakeholderRoleType, string>;
9
10
  export declare type StakeholderRoleType = typeof StakeholderRole[keyof typeof StakeholderRole];
10
11
  export declare const STAKEHOLDER_ROLES: StakeholderRoleType[];
11
12
  export declare function isStakeholderRole(val: string): val is StakeholderRoleType;
12
13
  export declare function canCreateCR(stakeholder: RegisterStakeholder): boolean;
13
14
  export declare function canImportCR(stakeholder: RegisterStakeholder): boolean;
15
+ export interface Contact {
16
+ label: string;
17
+ value: string;
18
+ notes?: string;
19
+ }
14
20
  /** Register stakeholder represents an individual. */
15
- interface _RegisterStakeholder {
21
+ export interface RegisterStakeholder {
16
22
  /** Stakeholder’s role wrt. the current register. */
17
- role: StakeholderRoleType;
23
+ roles: readonly StakeholderRoleType[];
18
24
  name: string;
19
25
  gitServerUsername?: string;
20
- parties: Party[];
21
- }
22
- interface Owner extends _RegisterStakeholder {
23
- role: typeof StakeholderRole.Owner;
24
- }
25
- export declare function isOwner(val: RegisterStakeholder): val is Owner;
26
- interface ControlBody extends _RegisterStakeholder {
27
- role: typeof StakeholderRole.ControlBody;
28
- }
29
- export declare function isControlBody(val: RegisterStakeholder): val is ControlBody;
30
- interface Manager extends _RegisterStakeholder {
31
- role: typeof StakeholderRole.Manager;
26
+ contacts: Contact[];
27
+ affiliations: {
28
+ [orgID: string]: StakeholderOrgAffiliation;
29
+ };
32
30
  }
33
- export declare function isManager(val: RegisterStakeholder): val is Manager;
34
- interface Submitter extends _RegisterStakeholder {
35
- role: typeof StakeholderRole.Submitter;
31
+ export interface StakeholderOrgAffiliation {
32
+ role: 'pointOfContact' | 'member';
36
33
  }
37
- export declare function isSubmitter(val: RegisterStakeholder): val is Submitter;
38
- interface Role {
39
- positionName: string;
40
- name?: never;
41
- organization: Organization;
42
- }
43
- interface Individual {
34
+ export declare function isOwner(val: RegisterStakeholder): boolean;
35
+ export declare function isControlBody(val: RegisterStakeholder): boolean;
36
+ export declare function isControlBodyReviewer(val: RegisterStakeholder): boolean;
37
+ export declare function isManager(val: RegisterStakeholder): boolean;
38
+ export declare function isSubmitter(val: RegisterStakeholder): boolean;
39
+ export interface Organization {
40
+ logoURL: string;
44
41
  name: string;
45
- positionName?: never;
46
- organization?: Organization;
47
42
  }
48
- declare type Organization<T = {
49
- logoURL: string[];
50
- name: string;
51
- }> = Partial<T> & Pick<T, keyof T>;
52
- declare type Party = (Individual | Role | Organization) & {
53
- contacts: {
54
- label: string;
55
- value: string;
56
- notes?: string;
57
- }[];
58
- };
59
- export declare function isIndividualParty(val: any): val is Individual;
60
- export declare type RegisterStakeholder = Owner | ControlBody | Manager | Submitter;
61
43
  export declare function isRegisterStakeholder(val: any): val is RegisterStakeholder;
62
- export {};
@@ -8,22 +8,30 @@ exports.canCreateCR = canCreateCR;
8
8
  exports.canImportCR = canImportCR;
9
9
  exports.isOwner = isOwner;
10
10
  exports.isControlBody = isControlBody;
11
+ exports.isControlBodyReviewer = isControlBodyReviewer;
11
12
  exports.isManager = isManager;
12
13
  exports.isSubmitter = isSubmitter;
13
- exports.isIndividualParty = isIndividualParty;
14
14
  exports.isRegisterStakeholder = isRegisterStakeholder;
15
- exports.STAKEHOLDER_ROLES = exports.StakeholderRole = void 0;
15
+ exports.STAKEHOLDER_ROLES = exports.StakeholderRoleLabels = exports.StakeholderRole = void 0;
16
16
  // Stakeholders
17
17
 
18
18
  /** Possible roles of a register stakeholder. */
19
19
  const StakeholderRole = {
20
20
  Owner: 'owner',
21
21
  ControlBody: 'control-body',
22
- ControlBodyRevew: 'control-body-reviewer',
22
+ ControlBodyReview: 'control-body-reviewer',
23
23
  Manager: 'manager',
24
24
  Submitter: 'submitter'
25
25
  };
26
26
  exports.StakeholderRole = StakeholderRole;
27
+ const StakeholderRoleLabels = {
28
+ owner: "Owner",
29
+ 'control-body': "Control body approver",
30
+ 'control-body-reviewer': "Control body reviewer",
31
+ manager: "Manager",
32
+ submitter: "Proposal submitter"
33
+ };
34
+ exports.StakeholderRoleLabels = StakeholderRoleLabels;
27
35
  const STAKEHOLDER_ROLES = Object.values(StakeholderRole);
28
36
  exports.STAKEHOLDER_ROLES = STAKEHOLDER_ROLES;
29
37
 
@@ -47,8 +55,7 @@ function isStakeholderRole(val) {
47
55
  function canCreateCR(stakeholder) {
48
56
  var _a;
49
57
 
50
- return [StakeholderRole.Submitter, StakeholderRole.Manager, // TODO: Temporary, owners shouldn’t be capable of creating CRs normally:
51
- StakeholderRole.Owner].indexOf(stakeholder.role) >= 0 && // Must have a Git server username (current limitation)
58
+ return isOwner(stakeholder) || isSubmitter(stakeholder) || isManager(stakeholder) && // Must have a Git server username (current limitation)
52
59
  // in order to be able to edit this proposal later.
53
60
  ((_a = stakeholder.gitServerUsername) === null || _a === void 0 ? void 0 : _a.trim()) !== '';
54
61
  }
@@ -56,32 +63,43 @@ function canCreateCR(stakeholder) {
56
63
  function canImportCR(stakeholder) {
57
64
  var _a;
58
65
 
59
- return [StakeholderRole.Manager, // TODO: Temporary, owners shouldn’t be capable of importing CRs normally:
60
- StakeholderRole.Owner].indexOf(stakeholder.role) >= 0 && // Must have a Git server username (current limitation)
66
+ return isManager(stakeholder) || isOwner(stakeholder) && // Must have a Git server username (current limitation)
61
67
  // in order to be able to edit this proposal later.
62
68
  ((_a = stakeholder.gitServerUsername) === null || _a === void 0 ? void 0 : _a.trim()) !== '';
63
69
  }
64
70
 
65
71
  function isOwner(val) {
66
- return val.role === StakeholderRole.Owner;
72
+ var _a;
73
+
74
+ return ((_a = val.roles) === null || _a === void 0 ? void 0 : _a.includes(StakeholderRole.Owner)) || val.role === StakeholderRole.Owner;
67
75
  }
68
76
 
69
77
  function isControlBody(val) {
70
- return val.role === StakeholderRole.ControlBody;
78
+ var _a;
79
+
80
+ return ((_a = val.roles) === null || _a === void 0 ? void 0 : _a.includes(StakeholderRole.ControlBody)) || val.role === StakeholderRole.ControlBody;
81
+ }
82
+
83
+ function isControlBodyReviewer(val) {
84
+ var _a;
85
+
86
+ return ((_a = val.roles) === null || _a === void 0 ? void 0 : _a.includes(StakeholderRole.ControlBodyReview)) || val.role === StakeholderRole.ControlBodyReview;
71
87
  }
72
88
 
73
89
  function isManager(val) {
74
- return val.role === StakeholderRole.Manager;
90
+ var _a;
91
+
92
+ return ((_a = val.roles) === null || _a === void 0 ? void 0 : _a.includes(StakeholderRole.Manager)) || val.role === StakeholderRole.Manager;
75
93
  }
76
94
 
77
95
  function isSubmitter(val) {
78
- return val.role === StakeholderRole.Submitter;
79
- }
96
+ var _a;
97
+
98
+ return ((_a = val.roles) === null || _a === void 0 ? void 0 : _a.includes(StakeholderRole.Submitter)) || val.role === StakeholderRole.Submitter;
99
+ } //export type RegisterStakeholder = Owner | ControlBody | Manager | Submitter
80
100
 
81
- function isIndividualParty(val) {
82
- return typeof val.name === 'string' && !val.hasOwnProperty('positionName');
83
- }
84
101
 
85
102
  function isRegisterStakeholder(val) {
86
- return val && val.hasOwnProperty('role') && isStakeholderRole(val.role) && val.hasOwnProperty('name');
103
+ return val && val.hasOwnProperty('name') && (val.hasOwnProperty('roles') && val.roles.every(isStakeholderRole) || val.hasOwnProperty('role') && isStakeholderRole(val.role) // TODO: obsolete
104
+ );
87
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stakeholder.js","sourceRoot":"","sources":["../../src/types/stakeholder.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,cAAc;IAC3B,gBAAgB,EAAE,uBAAuB;IACzC,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;CACd,CAAC;AAIX,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAA0B,CAAC;AAEzF,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,iBAAiB,CAAC,OAAO,CAAC,GAA0B,CAAC,IAAI,CAAC,CAAC;AACpE,CAAC;AAED,kCAAkC;AAClC,oDAAoD;AACpD,8BAA8B;AAC9B,qCAAqC;AACrC,qCAAqC;AACrC,+BAA+B;AAC/B,YAAY;AACZ,iEAAiE;AACjE,uDAAuD;AACvD,uFAAuF;AACvF,QAAQ;AACR,KAAK;AACL,GAAG;AAEH,MAAM,UAAU,WAAW,CAAC,WAAgC;;IAC1D,OAAO,CACL;QACE,eAAe,CAAC,SAAS;QACzB,eAAe,CAAC,OAAO;QACvB,yEAAyE;QACzE,eAAe,CAAC,KAAK;KACtB,CAAC,OAAO,CAAC,WAAW,CAAC,IAAW,CAAC,IAAI,CAAC;QACvC,uDAAuD;QACvD,mDAAmD;QACnD,CAAA,MAAA,WAAW,CAAC,iBAAiB,0CAAE,IAAI,EAAE,MAAK,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,WAAgC;;IAC1D,OAAO,CACL;QACE,eAAe,CAAC,OAAO;QACvB,0EAA0E;QAC1E,eAAe,CAAC,KAAK;KACtB,CAAC,OAAO,CAAC,WAAW,CAAC,IAAW,CAAC,IAAI,CAAC,CAAC;QACxC,uDAAuD;QACvD,mDAAmD;QACnD,CAAA,MAAA,WAAW,CAAC,iBAAiB,0CAAE,IAAI,EAAE,MAAK,EAAE,CAAC;AACjD,CAAC;AAiBD,MAAM,UAAU,OAAO,CAAC,GAAwB;IAC9C,OAAO,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC;AAC5C,CAAC;AAKD,MAAM,UAAU,aAAa,CAAC,GAAwB;IACpD,OAAO,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,WAAW,CAAC;AAClD,CAAC;AAKD,MAAM,UAAU,SAAS,CAAC,GAAwB;IAChD,OAAO,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,OAAO,CAAC;AAC9C,CAAC;AAKD,MAAM,UAAU,WAAW,CAAC,GAAwB;IAClD,OAAO,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,SAAS,CAAC;AAChD,CAAC;AA+BD,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,OAAO,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAC7E,CAAC;AAID,MAAM,UAAU,qBAAqB,CAAC,GAAQ;IAC5C,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;QAC1B,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAC3B,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AAChC,CAAC","sourcesContent":["// Stakeholders\n\n/** Possible roles of a register stakeholder. */\nexport const StakeholderRole = {\n Owner: 'owner',\n ControlBody: 'control-body',\n ControlBodyRevew: 'control-body-reviewer',\n Manager: 'manager',\n Submitter: 'submitter',\n} as const;\n\nexport type StakeholderRoleType = typeof StakeholderRole[keyof typeof StakeholderRole];\n\nexport const STAKEHOLDER_ROLES = Object.values(StakeholderRole) as StakeholderRoleType[];\n\nexport function isStakeholderRole(val: string): val is StakeholderRoleType {\n return STAKEHOLDER_ROLES.indexOf(val as StakeholderRoleType) >= 0;\n}\n\n//export function getStakeholders(\n// allStakeholders: readonly RegisterStakeholder[],\n// gitServerUsername: string,\n//): readonly RegisterStakeholder[] {\n// if (allStakeholders.length < 1) {\n// return Object.freeze([]);\n// } else {\n// const normalizedUsername = gitServerUsername.toLowerCase();\n// return Object.freeze(allStakeholders.filter(sh =>\n// sh.parties.find(p => p.gitServerUsername?.toLowerCase() === normalizedUsername)\n// ))\n// }\n//}\n\nexport function canCreateCR(stakeholder: RegisterStakeholder): boolean {\n return (\n [\n StakeholderRole.Submitter,\n StakeholderRole.Manager,\n // TODO: Temporary, owners shouldn’t be capable of creating CRs normally:\n StakeholderRole.Owner,\n ].indexOf(stakeholder.role as any) >= 0 &&\n // Must have a Git server username (current limitation)\n // in order to be able to edit this proposal later.\n stakeholder.gitServerUsername?.trim() !== '');\n}\n\nexport function canImportCR(stakeholder: RegisterStakeholder): boolean {\n return (\n [\n StakeholderRole.Manager,\n // TODO: Temporary, owners shouldn’t be capable of importing CRs normally:\n StakeholderRole.Owner,\n ].indexOf(stakeholder.role as any) >= 0) &&\n // Must have a Git server username (current limitation)\n // in order to be able to edit this proposal later.\n stakeholder.gitServerUsername?.trim() !== '';\n}\n\n/** Register stakeholder represents an individual. */\ninterface _RegisterStakeholder {\n /** Stakeholder’s role wrt. the current register. */\n role: StakeholderRoleType\n name: string\n\n // TODO: Make git server username per-party, instead of stakeholder-global?\n gitServerUsername?: string\n\n parties: Party[]\n}\n\ninterface Owner extends _RegisterStakeholder {\n role: typeof StakeholderRole.Owner\n}\nexport function isOwner(val: RegisterStakeholder): val is Owner {\n return val.role === StakeholderRole.Owner;\n}\n\ninterface ControlBody extends _RegisterStakeholder {\n role: typeof StakeholderRole.ControlBody\n}\nexport function isControlBody(val: RegisterStakeholder): val is ControlBody {\n return val.role === StakeholderRole.ControlBody;\n}\n\ninterface Manager extends _RegisterStakeholder {\n role: typeof StakeholderRole.Manager\n}\nexport function isManager(val: RegisterStakeholder): val is Manager {\n return val.role === StakeholderRole.Manager;\n}\n\ninterface Submitter extends _RegisterStakeholder {\n role: typeof StakeholderRole.Submitter\n}\nexport function isSubmitter(val: RegisterStakeholder): val is Submitter {\n return val.role === StakeholderRole.Submitter;\n}\n\n//interface NonEditingStakeholder extends _RegisterStakeholder {\n// role: 'owner'\n//}\n//export interface EditingStakeholder extends _RegisterStakeholder {\n// role: 'manager' | 'submitter'\n//}\n\ninterface Role {\n positionName: string\n name?: never\n organization: Organization\n}\n\ninterface Individual {\n name: string\n positionName?: never\n organization?: Organization\n}\n\n// Either logoURL or name or both must be present on an org here\ntype Organization<T = {\n logoURL: string[];\n name: string;\n}> = Partial<T> & Pick<T, keyof T>\n\ntype Party = (Individual | Role | Organization) & {\n contacts: { label: string, value: string, notes?: string }[]\n}\n\nexport function isIndividualParty(val: any): val is Individual {\n return typeof val.name === 'string' && !val.hasOwnProperty('positionName');\n}\n\nexport type RegisterStakeholder = Owner | ControlBody | Manager | Submitter\n\nexport function isRegisterStakeholder(val: any): val is RegisterStakeholder {\n return (\n val &&\n val.hasOwnProperty('role') &&\n isStakeholderRole(val.role) &&\n val.hasOwnProperty('name'));\n}\n"]}
1
+ {"version":3,"file":"stakeholder.js","sourceRoot":"","sources":["../../src/types/stakeholder.ts"],"names":[],"mappings":"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","sourcesContent":["// Stakeholders\n\n/** Possible roles of a register stakeholder. */\nexport const StakeholderRole = {\n Owner: 'owner',\n ControlBody: 'control-body',\n ControlBodyReview: 'control-body-reviewer',\n Manager: 'manager',\n Submitter: 'submitter',\n} as const;\n\nexport const StakeholderRoleLabels: Record<StakeholderRoleType, string> = {\n owner: \"Owner\",\n 'control-body': \"Control body approver\",\n 'control-body-reviewer': \"Control body reviewer\",\n manager: \"Manager\",\n submitter: \"Proposal submitter\",\n};\n\nexport type StakeholderRoleType = typeof StakeholderRole[keyof typeof StakeholderRole];\n\nexport const STAKEHOLDER_ROLES = Object.values(StakeholderRole) as StakeholderRoleType[];\n\nexport function isStakeholderRole(val: string): val is StakeholderRoleType {\n return STAKEHOLDER_ROLES.indexOf(val as StakeholderRoleType) >= 0;\n}\n\n//export function getStakeholders(\n// allStakeholders: readonly RegisterStakeholder[],\n// gitServerUsername: string,\n//): readonly RegisterStakeholder[] {\n// if (allStakeholders.length < 1) {\n// return Object.freeze([]);\n// } else {\n// const normalizedUsername = gitServerUsername.toLowerCase();\n// return Object.freeze(allStakeholders.filter(sh =>\n// sh.parties.find(p => p.gitServerUsername?.toLowerCase() === normalizedUsername)\n// ))\n// }\n//}\n\nexport function canCreateCR(stakeholder: RegisterStakeholder): boolean {\n return (\n isOwner(stakeholder) || isSubmitter(stakeholder) || isManager(stakeholder) && \n // Must have a Git server username (current limitation)\n // in order to be able to edit this proposal later.\n stakeholder.gitServerUsername?.trim() !== '');\n}\n\nexport function canImportCR(stakeholder: RegisterStakeholder): boolean {\n return (\n isManager(stakeholder) || isOwner(stakeholder) &&\n // Must have a Git server username (current limitation)\n // in order to be able to edit this proposal later.\n stakeholder.gitServerUsername?.trim() !== '');\n}\n\nexport interface Contact {\n label: string\n value: string\n notes?: string\n}\n\n/** Register stakeholder represents an individual. */\nexport interface RegisterStakeholder {\n /** Stakeholder’s role wrt. the current register. */\n //role: StakeholderRoleType\n roles: readonly StakeholderRoleType[]\n\n name: string\n\n gitServerUsername?: string\n\n contacts: Contact[]\n\n affiliations: {\n [orgID: string]: StakeholderOrgAffiliation\n }\n}\n\nexport interface StakeholderOrgAffiliation {\n role: 'pointOfContact' | 'member'\n}\n\nexport function isOwner(val: RegisterStakeholder): boolean {\n return val.roles?.includes(StakeholderRole.Owner)\n || (val as any).role === StakeholderRole.Owner;\n}\n\nexport function isControlBody(val: RegisterStakeholder): boolean {\n return val.roles?.includes(StakeholderRole.ControlBody)\n || (val as any).role === StakeholderRole.ControlBody;\n}\n\nexport function isControlBodyReviewer(val: RegisterStakeholder): boolean {\n return val.roles?.includes(StakeholderRole.ControlBodyReview)\n || (val as any).role === StakeholderRole.ControlBodyReview;\n}\n\nexport function isManager(val: RegisterStakeholder): boolean {\n return val.roles?.includes(StakeholderRole.Manager)\n || (val as any).role === StakeholderRole.Manager;\n}\n\nexport function isSubmitter(val: RegisterStakeholder): boolean {\n return val.roles?.includes(StakeholderRole.Submitter)\n || (val as any).role === StakeholderRole.Submitter;\n}\n\n// Either logoURL or name or both must be present on an org here\nexport interface Organization {\n logoURL: string\n name: string\n}\n\n//export type RegisterStakeholder = Owner | ControlBody | Manager | Submitter\n\nexport function isRegisterStakeholder(val: any): val is RegisterStakeholder {\n return (\n val\n && val.hasOwnProperty('name')\n && (\n (val.hasOwnProperty('roles') && val.roles.every(isStakeholderRole))\n || (val.hasOwnProperty('role') && isStakeholderRole(val.role)) // TODO: obsolete\n )\n );\n}\n"]}
package/types/views.d.ts CHANGED
@@ -90,6 +90,8 @@ export interface RegistryViewProps<Items extends ItemClassConfigurationSet = Rec
90
90
  * Not very useful since there are also preset searches in the browser now.
91
91
  */
92
92
  defaultSearchCriteria?: CriteriaGroup;
93
+ /** Group item classes */
94
+ itemClassGroups?: Record<string, readonly (keyof Items)[]>;
93
95
  /** Overrides CustomSidebarConfig, obviously. */
94
96
  CustomWorkspace?: React.FC<Record<never, never>>;
95
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/types/views.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\nimport type { ButtonProps, MenuItemProps } from '@blueprintjs/core';\nimport type { ObjectDatasetRequest, ObjectDatasetResponse, ValueHook } from '@riboseinc/paneron-extension-kit/types';\nimport type { InternalItemReference, Payload, RegisterItem, RegisterItemClass } from './item';\nimport type { CriteriaGroup } from '../views/FilterCriteria/models';\nimport type { AlterApprovedCR } from './cr';\n\n\n// Hooks\n\n/**\n * Mostly a wrapper around useObjectData, but coerces value type\n * (TODO: validate!) and takes into account change request from any\n * wrapping change request context. If a change request is present,\n * will substitute proposed item data unless `ignoreActiveCR` is set.\n *\n * NOTE: Despite the name, returns the entire RegisterItem,\n * not just the `.data` property with item payload.\n */\nexport type RegisterItemDataHook<P extends Payload = Payload> =\n (opts: { itemPaths: string[], ignoreActiveCR?: true }) => ValueHook<Record<string, RegisterItem<P> | null>>;\n\n\n// Extension configuration\n\n// TODO: Obsolete?\n// export interface ExtensionContext {\n// getRelatedItemClassConfiguration: (classID: string) => RelatedItemClassConfiguration\n// useRegisterItemData: RegisterItemDataHook\n// onJump?: () => void\n// }\n\nexport interface RegisterConfiguration\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>> {\n /**\n * Configuration for all items in this register.\n * This includes items in subregisters.\n */\n itemClassConfiguration: Items\n\n /**\n * Default expression used to sort an item.\n * Passed to useFilteredIndex().\n */\n keyExpression?: string\n\n /** Subregister information. */\n subregisters?: Subregisters<Items>\n}\n\nexport type Subregisters\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>> = {\n [subregisterID: string]: {\n title: string\n\n /** Names of item classes that go in this subregister. */\n itemClasses: (keyof Items)[]\n }\n};\n\nexport type ItemClassConfigurationSet = {\n [itemClassID: string]: ItemClassConfiguration<any>\n};\n\n\n\nexport interface ExportFormatConfiguration<P extends Payload> {\n /** The name of the export format. */\n label: string\n\n /**\n * Trailing part of the filename to save export as;\n * must include at least extension (with separator),\n * must not include any path prefix.\n */\n filenameExtension: string\n\n /**\n * The function that takes register item data and some helper functions\n * and is expected to return a blob.\n */\n exportItem: (\n itemData: RegisterItem<P>,\n opts: {\n getObjectData: (opts: ObjectDatasetRequest) => Promise<ObjectDatasetResponse>,\n getBlob: (val: string) => Promise<Uint8Array>,\n logger?: { log: Console[\"log\"], error: Console[\"error\"], debug: Console[\"debug\"] },\n },\n ) => Promise<Uint8Array>\n}\n\n\nexport interface ItemClassConfiguration<P extends Payload/*, F extends Field*/> {\n meta: RegisterItemClass\n\n itemCanBeSuperseded?: boolean\n // If false, items of this class cannot be superseded, only retired.\n // Default is true.\n\n /** Used to pre-populate item data e.g. when a new item is created. */\n defaults?: RegistryItemPayloadDefaults<P>\n\n validatePayload?: (item: P) => Promise<boolean>\n sanitizePayload?: (item: P) => Promise<P>\n\n // XXX: Confirm if obsolete and remove\n itemSorter?: (a: P, b: P) => number\n\n /**\n * Expression used to sort an item of this class.\n * Passed to useFilteredIndex().\n */\n keyExpression?: string\n\n exportFormats?: Readonly<ExportFormatConfiguration<P>[]>\n\n views: {\n listItemView: ItemListView<P>\n editView: ItemEditView<P>\n detailView?: ItemDetailView<P>\n }\n}\n\n\nexport interface RegistryViewProps\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>>\nextends RegisterConfiguration<Items> {\n /**\n * When search is initially opened, have this query pre-defined.\n * Not very useful since there are also preset searches in the browser now.\n */\n // TODO: Obsoluete?\n defaultSearchCriteria?: CriteriaGroup\n\n /** Overrides CustomSidebarConfig, obviously. */\n CustomWorkspace?: React.FC<Record<never, never>>\n\n /**\n * Default predicate for matching items\n * using quick search.\n *\n * Must return the search expression as text.\n *\n * Search expression must return a boolean and can access:\n *\n * - `obj`, which *should* be a RegisterItem instance\n * with `obj.data` being its class-specific payload.\n *\n * E.g., if all important item classes in your register\n * specify a `name` field:\n *\n * @example (searchQuery) => `obj.data?.name?.toLowerCase().indexOf(\"${searchQuery.toLowerCase()}\") >= 0`\n */\n getQuickSearchPredicate?: (quickSearchQuery: string) => string\n\n /**\n * Extension-provided additional views that don’t correspond\n * to entities like register item, change request, etc. handled by RegistryKit.\n */\n customViews?: CustomViewConfiguration[]\n\n /**\n * Allows to transform item data & proposals\n * after CB decision but before the changes are applied to the register.\n */\n alterApprovedCR?: AlterApprovedCR\n}\n\nexport interface CustomViewConfiguration {\n id: string\n label: string\n description: string\n view: React.FC<{\n /** View can support optional path for custom state/inner navigation (provisional). */\n path: string\n }>\n icon?: JSX.Element\n}\n\n\n// Item views\n\nexport interface ItemAction {\n getButtonProps:\n (item: RegisterItem<any>, itemClass: ItemClassConfiguration<any>, subregisterID?: string) =>\n ButtonProps | MenuItemProps\n}\n\nexport type RegistryView = React.FC<RegistryViewProps>\n\ntype RegistryItemPayloadDefaults<P extends Payload> =\n Partial<Omit<P, 'id'>>;\n\n/**\n * A small part of item class configuration,\n * useful e.g. for formatting related items.\n */\nexport type RelatedItemClassConfiguration = {\n title: string\n itemView: ItemListView<any>\n}\n\n\nexport interface RegistryItemViewProps<P extends Payload> {\n /**\n * Item reference.\n * Glossarist, for example, uses it to determine language subregister and set appropriate writing direction.\n */\n itemRef: Omit<InternalItemReference, 'itemID'> & { itemID?: InternalItemReference['itemID'] }\n\n /** Item data (payload). */\n itemData: P\n\n className?: string\n //subregisterID?: string\n\n /** Deprecated */\n useRegisterItemData?: any\n /** Deprecated */\n getRelatedItemClassConfiguration?: any\n}\n\nexport interface GenericRelatedItemViewProps {\n /** Currently selected item’s ref. */\n itemRef?: InternalItemReference\n\n /** Allows to grab a ref of the input displaying the selected item. */\n inputRef?: React.Ref<HTMLInputElement>\n\n /**\n * By default, clicking the item will spawn a tab via TabbedWorkspace context.\n * This prop can customize that behavior.\n */\n onJump?: () => void\n\n className?: string\n\n /**\n * Determines which item classes can be selected in the search dialog.\n * If undefined, *any* class can be chosen.\n * If empty list, no class can be chosen (weird).\n */\n availableClassIDs?: string[]\n\n // XXX: Check if obsolete, remove if unused\n itemSorter?: ItemClassConfiguration<any>[\"itemSorter\"]\n\n /** Called to auto-create an item (can’t auto-create if not provided) */\n onCreateNew?: () => Promise<InternalItemReference>\n\n /** Called when current item is cleared (can’t clear if not provided) */\n onClear?: () => void\n\n /** Called when a new item is selected (can’t change if not provided) */\n onChange?: (newRef: InternalItemReference) => void\n\n /** @deprecated subregisters no longer supported. */\n availableSubregisterIDs?: string[]\n\n /** @deprecated */\n useRegisterItemData?: any\n //useRegisterItemData: RegisterItemDataHook\n\n /** @deprecated */\n getRelatedItemClassConfiguration?: any\n //getRelatedItemClassConfiguration: ExtensionContext[\"getRelatedItemClassConfiguration\"]\n}\n\n\nexport type ItemEditView<P extends Payload> = React.FC<ItemEditViewProps<P>>;\n\nexport interface ItemEditViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n onChange?: (newData: P) => void\n onCreateRelatedItem?:\n (classID: string, subregisterID?: string) => Promise<InternalItemReference>\n}\n\nexport interface ItemDetailViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n //useRegisterItemData: RegisterItemDataHook\n}\n\nexport type ItemDetailView<P extends Payload> = React.FC<ItemDetailViewProps<P>>;\n\nexport interface ItemListViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n}\n\nexport type ItemListView<P extends Payload> = React.FC<ItemListViewProps<P>>;\n\nexport type LazyItemView = React.FC<{ itemID: string }>;\n"]}
1
+ {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/types/views.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\nimport type { ButtonProps, MenuItemProps } from '@blueprintjs/core';\nimport type { ObjectDatasetRequest, ObjectDatasetResponse, ValueHook } from '@riboseinc/paneron-extension-kit/types';\nimport type { InternalItemReference, Payload, RegisterItem, RegisterItemClass } from './item';\nimport type { CriteriaGroup } from '../views/FilterCriteria/models';\nimport type { AlterApprovedCR } from './cr';\n\n\n// Hooks\n\n/**\n * Mostly a wrapper around useObjectData, but coerces value type\n * (TODO: validate!) and takes into account change request from any\n * wrapping change request context. If a change request is present,\n * will substitute proposed item data unless `ignoreActiveCR` is set.\n *\n * NOTE: Despite the name, returns the entire RegisterItem,\n * not just the `.data` property with item payload.\n */\nexport type RegisterItemDataHook<P extends Payload = Payload> =\n (opts: { itemPaths: string[], ignoreActiveCR?: true }) => ValueHook<Record<string, RegisterItem<P> | null>>;\n\n\n// Extension configuration\n\n// TODO: Obsolete?\n// export interface ExtensionContext {\n// getRelatedItemClassConfiguration: (classID: string) => RelatedItemClassConfiguration\n// useRegisterItemData: RegisterItemDataHook\n// onJump?: () => void\n// }\n\nexport interface RegisterConfiguration\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>> {\n /**\n * Configuration for all items in this register.\n * This includes items in subregisters.\n */\n itemClassConfiguration: Items\n\n /**\n * Default expression used to sort an item.\n * Passed to useFilteredIndex().\n */\n keyExpression?: string\n\n /** Subregister information. */\n subregisters?: Subregisters<Items>\n}\n\nexport type Subregisters\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>> = {\n [subregisterID: string]: {\n title: string\n\n /** Names of item classes that go in this subregister. */\n itemClasses: (keyof Items)[]\n }\n};\n\nexport type ItemClassConfigurationSet = {\n [itemClassID: string]: ItemClassConfiguration<any>\n};\n\n\n\nexport interface ExportFormatConfiguration<P extends Payload> {\n /** The name of the export format. */\n label: string\n\n /**\n * Trailing part of the filename to save export as;\n * must include at least extension (with separator),\n * must not include any path prefix.\n */\n filenameExtension: string\n\n /**\n * The function that takes register item data and some helper functions\n * and is expected to return a blob.\n */\n exportItem: (\n itemData: RegisterItem<P>,\n opts: {\n getObjectData: (opts: ObjectDatasetRequest) => Promise<ObjectDatasetResponse>,\n getBlob: (val: string) => Promise<Uint8Array>,\n logger?: { log: Console[\"log\"], error: Console[\"error\"], debug: Console[\"debug\"] },\n },\n ) => Promise<Uint8Array>\n}\n\n\nexport interface ItemClassConfiguration<P extends Payload/*, F extends Field*/> {\n meta: RegisterItemClass\n\n itemCanBeSuperseded?: boolean\n // If false, items of this class cannot be superseded, only retired.\n // Default is true.\n\n /** Used to pre-populate item data e.g. when a new item is created. */\n defaults?: RegistryItemPayloadDefaults<P>\n\n validatePayload?: (item: P) => Promise<boolean>\n sanitizePayload?: (item: P) => Promise<P>\n\n // XXX: Confirm if obsolete and remove\n itemSorter?: (a: P, b: P) => number\n\n /**\n * Expression used to sort an item of this class.\n * Passed to useFilteredIndex().\n */\n keyExpression?: string\n\n exportFormats?: Readonly<ExportFormatConfiguration<P>[]>\n\n views: {\n listItemView: ItemListView<P>\n editView: ItemEditView<P>\n detailView?: ItemDetailView<P>\n }\n}\n\n\nexport interface RegistryViewProps\n<Items extends ItemClassConfigurationSet = Record<string, ItemClassConfiguration<any>>>\nextends RegisterConfiguration<Items> {\n /**\n * When search is initially opened, have this query pre-defined.\n * Not very useful since there are also preset searches in the browser now.\n */\n // TODO: Obsoluete?\n defaultSearchCriteria?: CriteriaGroup\n\n /** Group item classes */\n itemClassGroups?: Record<string, readonly (keyof Items)[]>\n\n /** Overrides CustomSidebarConfig, obviously. */\n CustomWorkspace?: React.FC<Record<never, never>>\n\n /**\n * Default predicate for matching items\n * using quick search.\n *\n * Must return the search expression as text.\n *\n * Search expression must return a boolean and can access:\n *\n * - `obj`, which *should* be a RegisterItem instance\n * with `obj.data` being its class-specific payload.\n *\n * E.g., if all important item classes in your register\n * specify a `name` field:\n *\n * @example (searchQuery) => `obj.data?.name?.toLowerCase().indexOf(\"${searchQuery.toLowerCase()}\") >= 0`\n */\n getQuickSearchPredicate?: (quickSearchQuery: string) => string\n\n /**\n * Extension-provided additional views that don’t correspond\n * to entities like register item, change request, etc. handled by RegistryKit.\n */\n customViews?: CustomViewConfiguration[]\n\n /**\n * Allows to transform item data & proposals\n * after CB decision but before the changes are applied to the register.\n */\n alterApprovedCR?: AlterApprovedCR\n}\n\nexport interface CustomViewConfiguration {\n id: string\n label: string\n description: string\n view: React.FC<{\n /** View can support optional path for custom state/inner navigation (provisional). */\n path: string\n }>\n icon?: JSX.Element\n}\n\n\n// Item views\n\nexport interface ItemAction {\n getButtonProps:\n (item: RegisterItem<any>, itemClass: ItemClassConfiguration<any>, subregisterID?: string) =>\n ButtonProps | MenuItemProps\n}\n\nexport type RegistryView = React.FC<RegistryViewProps>\n\ntype RegistryItemPayloadDefaults<P extends Payload> =\n Partial<Omit<P, 'id'>>;\n\n/**\n * A small part of item class configuration,\n * useful e.g. for formatting related items.\n */\nexport type RelatedItemClassConfiguration = {\n title: string\n itemView: ItemListView<any>\n}\n\n\nexport interface RegistryItemViewProps<P extends Payload> {\n /**\n * Item reference.\n * Glossarist, for example, uses it to determine language subregister and set appropriate writing direction.\n */\n itemRef: Omit<InternalItemReference, 'itemID'> & { itemID?: InternalItemReference['itemID'] }\n\n /** Item data (payload). */\n itemData: P\n\n className?: string\n //subregisterID?: string\n\n /** Deprecated */\n useRegisterItemData?: any\n /** Deprecated */\n getRelatedItemClassConfiguration?: any\n}\n\nexport interface GenericRelatedItemViewProps {\n /** Currently selected item’s ref. */\n itemRef?: InternalItemReference\n\n /** Allows to grab a ref of the input displaying the selected item. */\n inputRef?: React.Ref<HTMLInputElement>\n\n /**\n * By default, clicking the item will spawn a tab via TabbedWorkspace context.\n * This prop can customize that behavior.\n */\n onJump?: () => void\n\n className?: string\n\n /**\n * Determines which item classes can be selected in the search dialog.\n * If undefined, *any* class can be chosen.\n * If empty list, no class can be chosen (weird).\n */\n availableClassIDs?: string[]\n\n // XXX: Check if obsolete, remove if unused\n itemSorter?: ItemClassConfiguration<any>[\"itemSorter\"]\n\n /** Called to auto-create an item (can’t auto-create if not provided) */\n onCreateNew?: () => Promise<InternalItemReference>\n\n /** Called when current item is cleared (can’t clear if not provided) */\n onClear?: () => void\n\n /** Called when a new item is selected (can’t change if not provided) */\n onChange?: (newRef: InternalItemReference) => void\n\n /** @deprecated subregisters no longer supported. */\n availableSubregisterIDs?: string[]\n\n /** @deprecated */\n useRegisterItemData?: any\n //useRegisterItemData: RegisterItemDataHook\n\n /** @deprecated */\n getRelatedItemClassConfiguration?: any\n //getRelatedItemClassConfiguration: ExtensionContext[\"getRelatedItemClassConfiguration\"]\n}\n\n\nexport type ItemEditView<P extends Payload> = React.FC<ItemEditViewProps<P>>;\n\nexport interface ItemEditViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n onChange?: (newData: P) => void\n onCreateRelatedItem?:\n (classID: string, subregisterID?: string) => Promise<InternalItemReference>\n}\n\nexport interface ItemDetailViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n //useRegisterItemData: RegisterItemDataHook\n}\n\nexport type ItemDetailView<P extends Payload> = React.FC<ItemDetailViewProps<P>>;\n\nexport interface ItemListViewProps<P extends Payload> extends RegistryItemViewProps<P> {\n}\n\nexport type ItemListView<P extends Payload> = React.FC<ItemListViewProps<P>>;\n\nexport type LazyItemView = React.FC<{ itemID: string }>;\n"]}
@@ -2,7 +2,7 @@
2
2
  /// <reference types="react" />
3
3
  import type { ItemClassConfigurationSet, ItemClassConfiguration, RegisterItem, RegisterItemDataHook, Register, RegisterStakeholder, RelatedItemClassConfiguration, Subregisters, InternalItemReference, RegistryViewProps } from '../types';
4
4
  import { type Protocol } from './protocolRegistry';
5
- export interface BrowserCtx extends Pick<RegistryViewProps, "alterApprovedCR" | "defaultSearchCriteria" | "getQuickSearchPredicate" | "customViews"> {
5
+ export interface BrowserCtx extends Pick<RegistryViewProps, "alterApprovedCR" | "itemClassGroups" | "defaultSearchCriteria" | "getQuickSearchPredicate" | "customViews"> {
6
6
  itemClasses: ItemClassConfigurationSet;
7
7
  subregisters?: Subregisters;
8
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"BrowserCtx.js","sourceRoot":"","sources":["../../src/views/BrowserCtx.tsx"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAsGrC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAa;IAClD,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,yCAAyC;IACzC,oBAAoB,EAAE,IAAI;IAC1B,gBAAgB,EAAE,SAAS;IAC3B,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1B,KAAK,EAAE,EAAE;QACT,WAAW,EAAE,CAAC,CAAC;QACf,MAAM,EAAE,EAAE;QACV,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC;KACtB,CAAC;IACF,gCAAgC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,kCAAqB,EAAE,CAAC;CAClG,CAAC,CAAC","sourcesContent":["/** @jsx jsx */\n\nimport { jsx } from '@emotion/react';\nimport { createContext } from 'react';\nimport type {\n ItemClassConfigurationSet,\n ItemClassConfiguration,\n RegisterItem,\n RegisterItemDataHook,\n Register,\n RegisterStakeholder,\n RelatedItemClassConfiguration,\n // SaveProposalHandler,\n Subregisters,\n InternalItemReference,\n RegistryViewProps,\n} from '../types';\nimport { type Protocol } from './protocolRegistry';\n\n\n// TODO(perf): split into smaller contexts\nexport interface BrowserCtx extends Pick<RegistryViewProps,\n| \"alterApprovedCR\"\n| \"defaultSearchCriteria\"\n| \"getQuickSearchPredicate\"\n| \"customViews\"> {\n itemClasses: ItemClassConfigurationSet\n subregisters?: Subregisters\n\n /**\n * Stakeholder corresponding to the current user.\n * If current user is not a stakeholder, undefined.\n */\n stakeholder?: RegisterStakeholder\n\n /**\n * Set if no remote is configured.\n */\n offline?: true\n\n /**\n * Common “key expression” (used for sorting) across the register.\n * Should contain the expression itself, no “return” statement.\n */\n keyExpression?: string\n\n /**\n * Allows to access register metadata\n * (e.g., version, stakeholders).\n *\n * `undefined` if loading, `null` if unspecified.\n */\n registerMetadata?: Register | null\n\n /** Hook for getting register item data. */\n useRegisterItemData: RegisterItemDataHook\n\n /**\n * Invoked to navigate to an item.\n * In SPA tabbed context, could translate to `spawnTab()`;\n * in static web context, could translate to navigating browser location.\n */\n jumpTo?: (uri: `${Protocol}:${string}`) => void\n\n /**\n * If a register item is selected, provide its data here.\n *\n * If item data is still loading or invalid, `undefined`.\n * If item is not selected, `null`.\n */\n selectedRegisterItem?: {\n item: RegisterItem<any>\n ref: InternalItemReference\n itemClass: ItemClassConfiguration<any>\n } | null\n\n /**\n * Change request being drafted or reviewed.\n * `undefined` if loading, `null` if there is no active change request.\n */\n activeChangeRequestID?: string | null\n\n /**\n * Setter for `activeChangeRequest()`. Set to `null` to unset.\n */\n setActiveChangeRequestID?: (id: string | null) => void\n\n /**\n * An async function for retrieving data of register items\n * at given paths. For cases where the hook doesn’t work.\n *\n * If a path contains nothing or contains not a register item,\n * the result will be null.\n */\n // getRegisterItemData: (opts: { itemPaths: string[] }) => Promise<Record<string, RegisterItem<any> | null>>\n\n // onPropose?: SaveProposalHandler\n\n //selectedItemPath?: string\n\n /**\n * Given item class ID, returns a small subset of relevant class configuration data.\n */\n getRelatedItemClassConfiguration: (clsID: string) => RelatedItemClassConfiguration\n // TODO: Rename to just “get class config”\n};\n\nexport const BrowserCtx = createContext<BrowserCtx>({\n itemClasses: {},\n customViews: [],\n // getRegisterItemData: async () => ({}),\n selectedRegisterItem: null,\n registerMetadata: undefined,\n useRegisterItemData: () => ({\n value: {},\n _reqCounter: -1,\n errors: [],\n isUpdating: true,\n refresh: () => void 0,\n }),\n getRelatedItemClassConfiguration: () => ({ title: 'N/A', itemView: () => <span>Loading…</span> }),\n});\n"]}
1
+ {"version":3,"file":"BrowserCtx.js","sourceRoot":"","sources":["../../src/views/BrowserCtx.tsx"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAuGrC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAa;IAClD,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,yCAAyC;IACzC,oBAAoB,EAAE,IAAI;IAC1B,gBAAgB,EAAE,SAAS;IAC3B,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1B,KAAK,EAAE,EAAE;QACT,WAAW,EAAE,CAAC,CAAC;QACf,MAAM,EAAE,EAAE;QACV,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC;KACtB,CAAC;IACF,gCAAgC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,kCAAqB,EAAE,CAAC;CAClG,CAAC,CAAC","sourcesContent":["/** @jsx jsx */\n\nimport { jsx } from '@emotion/react';\nimport { createContext } from 'react';\nimport type {\n ItemClassConfigurationSet,\n ItemClassConfiguration,\n RegisterItem,\n RegisterItemDataHook,\n Register,\n RegisterStakeholder,\n RelatedItemClassConfiguration,\n // SaveProposalHandler,\n Subregisters,\n InternalItemReference,\n RegistryViewProps,\n} from '../types';\nimport { type Protocol } from './protocolRegistry';\n\n\n// TODO(perf): split into smaller contexts\nexport interface BrowserCtx extends Pick<RegistryViewProps,\n| \"alterApprovedCR\"\n| \"itemClassGroups\"\n| \"defaultSearchCriteria\"\n| \"getQuickSearchPredicate\"\n| \"customViews\"> {\n itemClasses: ItemClassConfigurationSet\n subregisters?: Subregisters\n\n /**\n * Stakeholder corresponding to the current user.\n * If current user is not a stakeholder, undefined.\n */\n stakeholder?: RegisterStakeholder\n\n /**\n * Set if no remote is configured.\n */\n offline?: true\n\n /**\n * Common “key expression” (used for sorting) across the register.\n * Should contain the expression itself, no “return” statement.\n */\n keyExpression?: string\n\n /**\n * Allows to access register metadata\n * (e.g., version, stakeholders).\n *\n * `undefined` if loading, `null` if unspecified.\n */\n registerMetadata?: Register | null\n\n /** Hook for getting register item data. */\n useRegisterItemData: RegisterItemDataHook\n\n /**\n * Invoked to navigate to an item.\n * In SPA tabbed context, could translate to `spawnTab()`;\n * in static web context, could translate to navigating browser location.\n */\n jumpTo?: (uri: `${Protocol}:${string}`) => void\n\n /**\n * If a register item is selected, provide its data here.\n *\n * If item data is still loading or invalid, `undefined`.\n * If item is not selected, `null`.\n */\n selectedRegisterItem?: {\n item: RegisterItem<any>\n ref: InternalItemReference\n itemClass: ItemClassConfiguration<any>\n } | null\n\n /**\n * Change request being drafted or reviewed.\n * `undefined` if loading, `null` if there is no active change request.\n */\n activeChangeRequestID?: string | null\n\n /**\n * Setter for `activeChangeRequest()`. Set to `null` to unset.\n */\n setActiveChangeRequestID?: (id: string | null) => void\n\n /**\n * An async function for retrieving data of register items\n * at given paths. For cases where the hook doesn’t work.\n *\n * If a path contains nothing or contains not a register item,\n * the result will be null.\n */\n // getRegisterItemData: (opts: { itemPaths: string[] }) => Promise<Record<string, RegisterItem<any> | null>>\n\n // onPropose?: SaveProposalHandler\n\n //selectedItemPath?: string\n\n /**\n * Given item class ID, returns a small subset of relevant class configuration data.\n */\n getRelatedItemClassConfiguration: (clsID: string) => RelatedItemClassConfiguration\n // TODO: Rename to just “get class config”\n};\n\nexport const BrowserCtx = createContext<BrowserCtx>({\n itemClasses: {},\n customViews: [],\n // getRegisterItemData: async () => ({}),\n selectedRegisterItem: null,\n registerMetadata: undefined,\n useRegisterItemData: () => ({\n value: {},\n _reqCounter: -1,\n errors: [],\n isUpdating: true,\n refresh: () => void 0,\n }),\n getRelatedItemClassConfiguration: () => ({ title: 'N/A', itemView: () => <span>Loading…</span> }),\n});\n"]}