@riboseinc/paneron-registry-kit 2.2.29 → 2.2.31

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 (85) hide show
  1. package/index.d.ts +4 -1
  2. package/index.js +26 -0
  3. package/index.js.map +1 -1
  4. package/item-classes/Tree.d.ts +5 -0
  5. package/item-classes/Tree.js +115 -0
  6. package/item-classes/Tree.js.map +1 -0
  7. package/item-classes/treeNodes.d.ts +12 -0
  8. package/item-classes/treeNodes.js +68 -0
  9. package/item-classes/treeNodes.js.map +1 -0
  10. package/package.json +2 -2
  11. package/proposals/actionableGroups/Tree.d.ts +7 -0
  12. package/proposals/actionableGroups/Tree.js +179 -0
  13. package/proposals/actionableGroups/Tree.js.map +1 -0
  14. package/proposals/actionableGroups/queries.d.ts +5 -0
  15. package/proposals/actionableGroups/queries.js +81 -0
  16. package/proposals/actionableGroups/queries.js.map +1 -0
  17. package/proposals/actionableGroups/treeNodes.d.ts +26 -0
  18. package/proposals/actionableGroups/treeNodes.js +94 -0
  19. package/proposals/actionableGroups/treeNodes.js.map +1 -0
  20. package/proposals/actionableGroups/types.d.ts +6 -0
  21. package/proposals/actionableGroups/types.js +5 -0
  22. package/proposals/actionableGroups/types.js.map +1 -0
  23. package/types/cr.d.ts +2 -1
  24. package/types/cr.js.map +1 -1
  25. package/types/item.d.ts +4 -1
  26. package/types/item.js.map +1 -1
  27. package/types/register.d.ts +4 -1
  28. package/types/register.js.map +1 -1
  29. package/types/stakeholder.d.ts +24 -41
  30. package/types/stakeholder.js +48 -16
  31. package/types/stakeholder.js.map +1 -1
  32. package/types/views.d.ts +4 -0
  33. package/types/views.js.map +1 -1
  34. package/views/BrowserCtx.d.ts +1 -1
  35. package/views/BrowserCtx.js.map +1 -1
  36. package/views/GenericRelatedItemView.js +21 -8
  37. package/views/GenericRelatedItemView.js.map +1 -1
  38. package/views/ItemDetailsDrawer.d.ts +1 -0
  39. package/views/ItemDetailsDrawer.js +4 -2
  40. package/views/ItemDetailsDrawer.js.map +1 -1
  41. package/views/ItemSearchDrawer.js +1 -1
  42. package/views/ItemSearchDrawer.js.map +1 -1
  43. package/views/Party.d.ts +0 -0
  44. package/views/Party.js +154 -0
  45. package/views/Party.js.map +1 -0
  46. package/views/RegisterStakeholder.js +2 -2
  47. package/views/RegisterStakeholder.js.map +1 -1
  48. package/views/StatefulTree.d.ts +19 -0
  49. package/views/StatefulTree.js +128 -0
  50. package/views/StatefulTree.js.map +1 -0
  51. package/views/change-request/ChangeRequestContext.js.map +1 -1
  52. package/views/change-request/TransitionHistory.js +6 -3
  53. package/views/change-request/TransitionHistory.js.map +1 -1
  54. package/views/change-request/TransitionOptions.js +37 -13
  55. package/views/change-request/TransitionOptions.js.map +1 -1
  56. package/views/detail/RegisterHome/index.js +20 -79
  57. package/views/detail/RegisterHome/index.js.map +1 -1
  58. package/views/detail/RegisterItem/index.d.ts +2 -2
  59. package/views/detail/RegisterItem/index.js +21 -14
  60. package/views/detail/RegisterItem/index.js.map +1 -1
  61. package/views/detail/RegisterItemClass.d.ts +12 -0
  62. package/views/detail/RegisterItemClass.js +98 -0
  63. package/views/detail/RegisterItemClass.js.map +1 -0
  64. package/views/detail/RegisterMeta/RegisterMetaForm.js +272 -114
  65. package/views/detail/RegisterMeta/RegisterMetaForm.js.map +1 -1
  66. package/views/detail/RegisterMeta/index.js +1 -1
  67. package/views/detail/RegisterMeta/index.js.map +1 -1
  68. package/views/hooks/useStakeholder.d.ts +0 -0
  69. package/views/hooks/useStakeholder.js +1 -0
  70. package/views/hooks/useStakeholder.js.map +1 -0
  71. package/views/index.d.ts +1 -0
  72. package/views/index.js +71 -8
  73. package/views/index.js.map +1 -1
  74. package/views/protocolRegistry.d.ts +1 -0
  75. package/views/protocolRegistry.js +4 -0
  76. package/views/protocolRegistry.js.map +1 -1
  77. package/views/sidebar/Browse/index.js +8 -44
  78. package/views/sidebar/Browse/index.js.map +1 -1
  79. package/views/sidebar/Registration/index.js.map +1 -1
  80. package/views/sidebar/index.d.ts +2 -1
  81. package/views/sidebar/index.js +77 -62
  82. package/views/sidebar/index.js.map +1 -1
  83. package/views/util.d.ts +5 -0
  84. package/views/util.js +42 -4
  85. package/views/util.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/proposals/actionableGroups/queries.ts"],"names":[],"mappings":"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","sourcesContent":["import { State } from '../../types/cr';\nimport type { StakeholderRoleType } from '../../types';\nimport type { ActionableProposalGroup } from './types';\n\n\nexport function getActionableProposalGroupsForRole(role: StakeholderRoleType): readonly ActionableProposalGroup[] {\n return CR_QUERIES_FOR_ROLES.filter(([, roles]) => roles.has(role));\n}\n\nexport function getActionableProposalGroupsForRoles(roles: readonly StakeholderRoleType[]): readonly ActionableProposalGroup[] {\n return roles.flatMap(getActionableProposalGroupsForRole);\n}\n\n\nexport const CR_BASE_QUERY = 'objPath.indexOf(\"/proposals/\") === 0 && objPath.endsWith(\"main.yaml\")';\n\nconst CR_QUERIES_FOR_ROLES: readonly ActionableProposalGroup[] =\n[\n ['My Drafts', new Set(['submitter', 'manager', 'control-body', 'owner']), function submitterProposals(stakeholder) {\n if (stakeholder && stakeholder.gitServerUsername) {\n const stakeholderCondition = `obj.submittingStakeholderGitServerUsername === \"${stakeholder.gitServerUsername}\"`;\n const query = `(obj.state === \"${State.DRAFT}\" || obj.state === \"${State.RETURNED_FOR_CLARIFICATION}\") && (${stakeholderCondition})`;\n return query;\n } else {\n return 'false';\n }\n }],\n ['My Rejected', new Set(['submitter', 'manager', 'control-body', 'owner']), function submitterProposals(stakeholder) {\n // Rejections are actionable because they can be appealed by the submitter.\n if (stakeholder && stakeholder.gitServerUsername) {\n const stakeholderCondition = `obj.submittingStakeholderGitServerUsername === \"${stakeholder.gitServerUsername}\"`;\n const query = `(obj.state === \"${State.REJECTED}\") && (${stakeholderCondition})`;\n return query;\n } else {\n return 'false';\n }\n }],\n ['Everyone’s Drafts or Returned', new Set(['manager', 'control-body', 'owner']), function submitterProposals(stakeholder) {\n if (stakeholder && stakeholder.gitServerUsername) {\n const stakeholderCondition = `obj.submittingStakeholderGitServerUsername !== \"${stakeholder.gitServerUsername}\"`;\n const query = `(obj.state === \"${State.DRAFT}\" || obj.state === \"${State.RETURNED_FOR_CLARIFICATION}\") && (${stakeholderCondition})`;\n return query;\n } else {\n return 'false';\n }\n }],\n // ['latest reviewed', new Set(['submitter', 'manager', 'control-body', 'owner']), function submitterProposals(stakeholder) {\n // // TODO: Should filter only rejected perhaps?\n // // Approved/accepted proposals can be shown in another (public) area.\n // if (stakeholder && stakeholder.gitServerUsername) {\n // const stakeholderCondition = stakeholder?.role !== 'submitter'\n // ? 'true'\n // : `obj.submittingStakeholderGitServerUsername === \"${stakeholder.gitServerUsername}\"`;\n // // Don’t show drafts in the list of pending proposals, unless it’s user’s own drafts.\n // const query = `(obj.state === \"${State.ACCEPTED} || obj.state === \"${State.REJECTED} || obj.state === \"${State.REJECTION_UPHELD_ON_APPEAL}\"\") && ${stakeholderCondition}`;\n // return query;\n // } else {\n // return 'false';\n // }\n // // TODO: Implement limit\n // }],\n // ['latest withdrawn', new Set(['submitter', 'manager', 'control-body', 'owner']), function submitterProposals(stakeholder) {\n // if (stakeholder && stakeholder.gitServerUsername) {\n // const stakeholderCondition = stakeholder?.role !== 'submitter'\n // ? 'true'\n // : `obj.submittingStakeholderGitServerUsername === \"${stakeholder.gitServerUsername}\"`;\n // // Don’t show drafts in the list of pending proposals, unless it’s user’s own drafts.\n // const query = `(obj.state === \"${State.WITHDRAWN}\" || obj.state === \"${State.APPEAL_WITHDRAWN}\") && ${stakeholderCondition}`;\n // return query;\n // } else {\n // return 'false';\n // }\n // // TODO: Implement limit\n // }],\n ['Pending Owner Appeal Review', new Set(['owner']), function ownerProposals() {\n return `obj.state === \"${State.APPEALED}\"`;\n }],\n ['Pending Control Body Review', new Set(['control-body', 'owner']), function cbProposals() {\n return `obj.state === \"${State.SUBMITTED_FOR_CONTROL_BODY_REVIEW}\"`;\n }],\n ['Pending Manager Review', new Set(['manager', 'control-body', 'owner']), function managerProposals() {\n return `obj.state === \"${State.PROPOSED}\"`;\n }],\n] as const;\n"]}
@@ -0,0 +1,26 @@
1
+ /** @jsx jsx */
2
+ /** @jsxFrag React.Fragment */
3
+ import type { TreeNodeInfo } from '@blueprintjs/core';
4
+ import type { RegisterStakeholder } from '../../types';
5
+ import type { SomeCR as CR } from '../../types/cr';
6
+ import type { ActionableProposalGroup } from './types';
7
+ export declare type ActionableProposalTreeNode = TreeNodeInfo<{
8
+ type: 'group' | 'item';
9
+ }>;
10
+ interface ActionableProposalGroupResult {
11
+ groupLabel: string;
12
+ proposals: CR[] | undefined;
13
+ }
14
+ export declare function getActionableProposalGroupsAsTreeNodes(groups: readonly ActionableProposalGroupResult[], opts?: {
15
+ expandedGroupLabels?: Set<string>;
16
+ selectedGroup?: string;
17
+ selectedCRID?: string;
18
+ activeCRID?: string;
19
+ }): ActionableProposalTreeNode[];
20
+ export declare function getMapReduceChainsForActionableProposalGroups(proposalGroups: readonly ActionableProposalGroup[], stakeholder: RegisterStakeholder): {
21
+ [x: string]: {
22
+ mapFunc: string;
23
+ predicateFunc: string;
24
+ };
25
+ };
26
+ export {};
@@ -0,0 +1,94 @@
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: proposal.justification,
68
+ isSelected: (_a = opts === null || opts === void 0 ? void 0 : opts.isSelected) !== null && _a !== void 0 ? _a : false,
69
+ icon: 'lightbulb',
70
+ secondaryLabel: (opts === null || opts === void 0 ? void 0 : opts.isActive) ? activeCRMarker : undefined,
71
+ nodeData: {
72
+ type: 'item'
73
+ }
74
+ };
75
+ }
76
+
77
+ function getMapReduceChainsForActionableProposalGroups(proposalGroups, stakeholder) {
78
+ return proposalGroups.map(([label,, queryGetter]) => {
79
+ const query = queryGetter(stakeholder);
80
+ const predicateFunc = `
81
+ const objPath = key, obj = value;
82
+ return ((${_queries.CR_BASE_QUERY}) && (${query}));
83
+ `;
84
+ const mapFunc = `emit(value);`;
85
+ return {
86
+ [label]: {
87
+ mapFunc,
88
+ predicateFunc
89
+ }
90
+ };
91
+ }).reduce((prev, curr) => ({ ...prev,
92
+ ...curr
93
+ }), {});
94
+ }
@@ -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: proposal.justification,\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
@@ -2,7 +2,7 @@
2
2
  import type React from 'react';
3
3
  import type { DatasetContext } from '@riboseinc/paneron-extension-kit/types/renderer';
4
4
  import type { ProposalSet } from './proposal';
5
- import { type RegisterStakeholder } from './stakeholder';
5
+ import type { RegisterStakeholder } from './stakeholder';
6
6
  import type { RegisterItem } from './item';
7
7
  export declare function isSubmittedBy(stakeholder: RegisterStakeholder, cr: Base): boolean;
8
8
  declare type ItemDataset = Record<string, RegisterItem<any> | null>;
@@ -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"]}
package/types/item.d.ts CHANGED
@@ -37,7 +37,10 @@ export interface RegisterItem<P extends Payload = Payload> {
37
37
  id: string;
38
38
  status: ItemStatus;
39
39
  dateAccepted: Date;
40
- /** UUID of change request that defined the current version. */
40
+ /**
41
+ * UUID of change request that defined the current version.
42
+ * (Provisional.)
43
+ */
41
44
  amendedInCR?: string;
42
45
  supersededBy?: InternalItemReference[];
43
46
  supersedes?: InternalItemReference[];
package/types/item.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"item.js","sourceRoot":"","sources":["../../src/types/item.ts"],"names":[],"mappings":"AAKA,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,OAAO;IACP,YAAY;IACZ,SAAS;IACT,SAAS;CACD,CAAC;AA2BX,MAAM,UAAU,uBAAuB,CAAC,GAAQ;IAC9C,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC5B,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC;QAC7B,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ;QAChC,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAA0B;IAC9C,MAAM,EAAE,qBAAqB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,aAAa,EAAE,SAAS;CAChB,CAAC;AA0CX,MAAM,UAAU,cAAc,CAAC,GAAQ;IACrC,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;QACxB,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,WAAW;QAC/B,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC5B,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CACvC,CAAC;AACJ,CAAC","sourcesContent":["import type { Citation, LocalizedAlternative } from './util';\n\n\nexport type Payload = Record<string, any>\n\nconst ITEM_STATUSES = [\n 'submitted',\n 'valid',\n 'superseded',\n 'retired',\n 'invalid',\n] as const;\n\nexport type ItemStatus = typeof ITEM_STATUSES[number];\n\n\nexport interface RegisterItemID {\n classID: string\n itemID: string\n}\n\n\nexport interface RegisterItemClass {\n id: string\n title: string\n description?: string\n alternativeNames?: Readonly<LocalizedAlternative<string>[]>\n}\n\ninterface ItemReference {\n registerID: string\n subregisterID?: string\n classID: string\n itemID: string\n}\n\nexport type InternalItemReference = Omit<ItemReference, 'registerID'>\n\nexport function isInternalItemReference(val: any): val is InternalItemReference {\n return (\n val &&\n val.hasOwnProperty('itemID') &&\n val.hasOwnProperty('classID') &&\n typeof val['itemID'] == 'string' &&\n typeof val['classID'] == 'string'\n );\n}\n\nexport const DUMMY_REF: InternalItemReference = {\n itemID: 'NONEXISTENT_ITEM_ID',\n classID: 'NONEXISTENT_CLASS_ID',\n subregisterID: undefined,\n} as const;\n\n\ninterface AbstractItemSource {\n type: string\n}\ninterface PaneronRegisterItemSource extends AbstractItemSource {\n type: 'paneron_register'\n itemRef: ItemReference\n}\ninterface ExternalSource extends AbstractItemSource {\n type: 'external'\n citation: Citation\n}\ntype RegisterItemSource = PaneronRegisterItemSource | ExternalSource\n\nexport interface RegisterItem<P extends Payload = Payload> {\n id: string // UUID\n\n status: ItemStatus\n\n dateAccepted: Date\n // This is a mandatory property, since until their acceptance items “live” as part of their corresponding change requests\n\n /** UUID of change request that defined the current version. */\n amendedInCR?: string\n\n // TODO: Denormalized, should be validated with consistency checks\n supersededBy?: InternalItemReference[]\n supersedes?: InternalItemReference[]\n\n /**\n * Register item data. Domain-specific. May include additional human-readable identifiers.\n * In ISO 19135-1 was represented by “definition”.\n */\n data: P\n\n source?: RegisterItemSource\n // TODO: Citations were suggested to be moved to proposals, as motivating/substantiating evidence.\n // TODO: Register item, however, should have a relationship that points to the original proto-item from another register.\n}\n\nexport function isRegisterItem(val: any): val is RegisterItem<any> {\n return (\n val &&\n val.hasOwnProperty('id') &&\n val.hasOwnProperty('data') &&\n typeof val.data !== 'undefined' &&\n val.hasOwnProperty('status') &&\n ITEM_STATUSES.indexOf(val.status) >= 0\n );\n}\n"]}
1
+ {"version":3,"file":"item.js","sourceRoot":"","sources":["../../src/types/item.ts"],"names":[],"mappings":"AAKA,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,OAAO;IACP,YAAY;IACZ,SAAS;IACT,SAAS;CACD,CAAC;AA2BX,MAAM,UAAU,uBAAuB,CAAC,GAAQ;IAC9C,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC5B,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC;QAC7B,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ;QAChC,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAA0B;IAC9C,MAAM,EAAE,qBAAqB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,aAAa,EAAE,SAAS;CAChB,CAAC;AA6CX,MAAM,UAAU,cAAc,CAAC,GAAQ;IACrC,OAAO,CACL,GAAG;QACH,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;QACxB,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,WAAW;QAC/B,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC5B,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CACvC,CAAC;AACJ,CAAC","sourcesContent":["import type { Citation, LocalizedAlternative } from './util';\n\n\nexport type Payload = Record<string, any>\n\nconst ITEM_STATUSES = [\n 'submitted',\n 'valid',\n 'superseded',\n 'retired',\n 'invalid',\n] as const;\n\nexport type ItemStatus = typeof ITEM_STATUSES[number];\n\n\nexport interface RegisterItemID {\n classID: string\n itemID: string\n}\n\n\nexport interface RegisterItemClass {\n id: string\n title: string\n description?: string\n alternativeNames?: Readonly<LocalizedAlternative<string>[]>\n}\n\ninterface ItemReference {\n registerID: string\n subregisterID?: string\n classID: string\n itemID: string\n}\n\nexport type InternalItemReference = Omit<ItemReference, 'registerID'>\n\nexport function isInternalItemReference(val: any): val is InternalItemReference {\n return (\n val &&\n val.hasOwnProperty('itemID') &&\n val.hasOwnProperty('classID') &&\n typeof val['itemID'] == 'string' &&\n typeof val['classID'] == 'string'\n );\n}\n\nexport const DUMMY_REF: InternalItemReference = {\n itemID: 'NONEXISTENT_ITEM_ID',\n classID: 'NONEXISTENT_CLASS_ID',\n subregisterID: undefined,\n} as const;\n\n\ninterface AbstractItemSource {\n type: string\n}\ninterface PaneronRegisterItemSource extends AbstractItemSource {\n type: 'paneron_register'\n itemRef: ItemReference\n}\ninterface ExternalSource extends AbstractItemSource {\n type: 'external'\n citation: Citation\n}\ntype RegisterItemSource = PaneronRegisterItemSource | ExternalSource\n\nexport interface RegisterItem<P extends Payload = Payload> {\n id: string // UUID\n\n status: ItemStatus\n\n dateAccepted: Date\n // This is a mandatory property, since until their acceptance items “live” as part of their corresponding change requests\n\n /**\n * UUID of change request that defined the current version.\n * (Provisional.)\n */\n amendedInCR?: string\n\n // TODO: Denormalized, should be validated with consistency checks\n supersededBy?: InternalItemReference[]\n supersedes?: InternalItemReference[]\n\n /**\n * Register item data. Domain-specific. May include additional human-readable identifiers.\n * In ISO 19135-1 was represented by “definition”.\n */\n data: P\n\n source?: RegisterItemSource\n // TODO: Citations were suggested to be moved to proposals, as motivating/substantiating evidence.\n // TODO: Register item, however, should have a relationship that points to the original proto-item from another register.\n}\n\nexport function isRegisterItem(val: any): val is RegisterItem<any> {\n return (\n val &&\n val.hasOwnProperty('id') &&\n val.hasOwnProperty('data') &&\n typeof val.data !== 'undefined' &&\n val.hasOwnProperty('status') &&\n ITEM_STATUSES.indexOf(val.status) >= 0\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,59 +2,42 @@
2
2
  export declare const StakeholderRole: {
3
3
  readonly Owner: "owner";
4
4
  readonly ControlBody: "control-body";
5
+ readonly ControlBodyReview: "control-body-reviewer";
5
6
  readonly Manager: "manager";
6
7
  readonly Submitter: "submitter";
7
8
  };
9
+ export declare const StakeholderRoleLabels: Record<StakeholderRoleType, string>;
8
10
  export declare type StakeholderRoleType = typeof StakeholderRole[keyof typeof StakeholderRole];
9
11
  export declare const STAKEHOLDER_ROLES: StakeholderRoleType[];
10
12
  export declare function isStakeholderRole(val: string): val is StakeholderRoleType;
11
13
  export declare function canCreateCR(stakeholder: RegisterStakeholder): boolean;
12
14
  export declare function canImportCR(stakeholder: RegisterStakeholder): boolean;
13
- /** “Abstract” register stakeholder type. */
14
- interface _RegisterStakeholder {
15
- role: StakeholderRoleType;
15
+ export interface Contact {
16
+ label: string;
17
+ value: string;
18
+ notes?: string;
19
+ }
20
+ /** Register stakeholder represents an individual. */
21
+ export interface RegisterStakeholder {
22
+ /** Stakeholder’s role wrt. the current register. */
23
+ roles: readonly StakeholderRoleType[];
16
24
  name: string;
17
25
  gitServerUsername?: string;
18
- parties: Party[];
19
- }
20
- interface Owner extends _RegisterStakeholder {
21
- role: typeof StakeholderRole.Owner;
22
- }
23
- export declare function isOwner(val: RegisterStakeholder): val is Owner;
24
- interface ControlBody extends _RegisterStakeholder {
25
- role: typeof StakeholderRole.ControlBody;
26
- }
27
- export declare function isControlBody(val: RegisterStakeholder): val is ControlBody;
28
- interface Manager extends _RegisterStakeholder {
29
- role: typeof StakeholderRole.Manager;
26
+ contacts: Contact[];
27
+ affiliations: {
28
+ [orgID: string]: StakeholderOrgAffiliation;
29
+ };
30
30
  }
31
- export declare function isManager(val: RegisterStakeholder): val is Manager;
32
- interface Submitter extends _RegisterStakeholder {
33
- role: typeof StakeholderRole.Submitter;
31
+ export interface StakeholderOrgAffiliation {
32
+ role: 'pointOfContact' | 'member';
34
33
  }
35
- export declare function isSubmitter(val: RegisterStakeholder): val is Submitter;
36
- interface Role {
37
- positionName: string;
38
- name?: never;
39
- organization: Organization;
40
- }
41
- 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;
42
41
  name: string;
43
- positionName?: never;
44
- organization?: Organization;
45
42
  }
46
- declare type Organization<T = {
47
- logoURL: string[];
48
- name: string;
49
- }> = Partial<T> & Pick<T, keyof T>;
50
- declare type Party = (Individual | Role | Organization) & {
51
- contacts: {
52
- label: string;
53
- value: string;
54
- notes?: string;
55
- }[];
56
- };
57
- export declare function isIndividualParty(val: any): val is Individual;
58
- export declare type RegisterStakeholder = Owner | ControlBody | Manager | Submitter;
59
43
  export declare function isRegisterStakeholder(val: any): val is RegisterStakeholder;
60
- export {};
@@ -8,33 +8,54 @@ 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
+ ControlBodyReview: 'control-body-reviewer',
22
23
  Manager: 'manager',
23
24
  Submitter: 'submitter'
24
25
  };
25
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;
26
35
  const STAKEHOLDER_ROLES = Object.values(StakeholderRole);
27
36
  exports.STAKEHOLDER_ROLES = STAKEHOLDER_ROLES;
28
37
 
29
38
  function isStakeholderRole(val) {
30
39
  return STAKEHOLDER_ROLES.indexOf(val) >= 0;
31
- }
40
+ } //export function getStakeholders(
41
+ // allStakeholders: readonly RegisterStakeholder[],
42
+ // gitServerUsername: string,
43
+ //): readonly RegisterStakeholder[] {
44
+ // if (allStakeholders.length < 1) {
45
+ // return Object.freeze([]);
46
+ // } else {
47
+ // const normalizedUsername = gitServerUsername.toLowerCase();
48
+ // return Object.freeze(allStakeholders.filter(sh =>
49
+ // sh.parties.find(p => p.gitServerUsername?.toLowerCase() === normalizedUsername)
50
+ // ))
51
+ // }
52
+ //}
53
+
32
54
 
33
55
  function canCreateCR(stakeholder) {
34
56
  var _a;
35
57
 
36
- return [StakeholderRole.Submitter, StakeholderRole.Manager, // TODO: Temporary, owners shouldn’t be capable of creating CRs normally:
37
- 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)
38
59
  // in order to be able to edit this proposal later.
39
60
  ((_a = stakeholder.gitServerUsername) === null || _a === void 0 ? void 0 : _a.trim()) !== '';
40
61
  }
@@ -42,32 +63,43 @@ function canCreateCR(stakeholder) {
42
63
  function canImportCR(stakeholder) {
43
64
  var _a;
44
65
 
45
- return [StakeholderRole.Manager, // TODO: Temporary, owners shouldn’t be capable of importing CRs normally:
46
- 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)
47
67
  // in order to be able to edit this proposal later.
48
68
  ((_a = stakeholder.gitServerUsername) === null || _a === void 0 ? void 0 : _a.trim()) !== '';
49
69
  }
50
70
 
51
71
  function isOwner(val) {
52
- 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;
53
75
  }
54
76
 
55
77
  function isControlBody(val) {
56
- 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;
57
87
  }
58
88
 
59
89
  function isManager(val) {
60
- 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;
61
93
  }
62
94
 
63
95
  function isSubmitter(val) {
64
- return val.role === StakeholderRole.Submitter;
65
- }
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
66
100
 
67
- function isIndividualParty(val) {
68
- return typeof val.name === 'string' && !val.hasOwnProperty('positionName');
69
- }
70
101
 
71
102
  function isRegisterStakeholder(val) {
72
- 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
+ );
73
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,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,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;AAgBD,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 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\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/** “Abstract” register stakeholder type. */\ninterface _RegisterStakeholder {\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":"AAAA,eAAe;AAEf,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,cAAc;IAC3B,iBAAiB,EAAE,uBAAuB;IAC1C,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;CACd,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAwC;IACxE,KAAK,EAAE,OAAO;IACd,cAAc,EAAE,uBAAuB;IACvC,uBAAuB,EAAE,uBAAuB;IAChD,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,oBAAoB;CAChC,CAAC;AAIF,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,OAAO,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC;QAC1E,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,SAAS,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,WAAW,CAAC;QAC9C,uDAAuD;QACvD,mDAAmD;QACnD,CAAA,MAAA,WAAW,CAAC,iBAAiB,0CAAE,IAAI,EAAE,MAAK,EAAE,CAAC,CAAC;AAClD,CAAC;AA6BD,MAAM,UAAU,OAAO,CAAC,GAAwB;;IAC9C,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC;WAC3C,GAAW,CAAC,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAwB;;IACpD,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC;WACjD,GAAW,CAAC,IAAI,KAAK,eAAe,CAAC,WAAW,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAwB;;IAC5D,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,CAAC,eAAe,CAAC,iBAAiB,CAAC;WACvD,GAAW,CAAC,IAAI,KAAK,eAAe,CAAC,iBAAiB,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAwB;;IAChD,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC;WAC7C,GAAW,CAAC,IAAI,KAAK,eAAe,CAAC,OAAO,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAwB;;IAClD,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC;WAC/C,GAAW,CAAC,IAAI,KAAK,eAAe,CAAC,SAAS,CAAC;AACvD,CAAC;AAQD,6EAA6E;AAE7E,MAAM,UAAU,qBAAqB,CAAC,GAAQ;IAC5C,OAAO,CACL,GAAG;WACA,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;WAC1B,CACD,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;eAChE,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB;SACjF,CACF,CAAC;AACJ,CAAC","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,10 @@ 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)[]>;
95
+ /** Overrides CustomSidebarConfig, obviously. */
96
+ CustomWorkspace?: React.FC<Record<never, never>>;
93
97
  /**
94
98
  * Default predicate for matching items
95
99
  * using quick search.