@zeniai/web-components 4.1.67-betaJK1 → 4.1.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{SessionTimeoutPopup-Cv0c2zTy.cjs → SessionTimeoutPopup-C303Wa5k.cjs} +15042 -14541
- package/dist/{SessionTimeoutPopup-CE3ZYJij.js → SessionTimeoutPopup-DVDz8HcJ.js} +70621 -68676
- package/dist/appLocale.d.ts +115 -10
- package/dist/assets/interface/dnd-handle.svg +8 -0
- package/dist/assets/interface/flag.svg +4 -3
- package/dist/cockpit.cjs.js +2 -2
- package/dist/cockpit.esm.js +289 -284
- package/dist/components/common/zeniDatePicker/ZeniDatePickerField.d.ts +1 -2
- package/dist/components/commonSetUp/approval/AmountConditionRow.d.ts +21 -0
- package/dist/components/commonSetUp/approval/ApprovalRuleSection.d.ts +70 -3
- package/dist/components/commonSetUp/approval/ApprovalRuleSectionV1.d.ts +14 -0
- package/dist/components/commonSetUp/approval/ApprovalStageRow.d.ts +121 -0
- package/dist/components/commonSetUp/approval/ApprovalStagesSection.d.ts +66 -0
- package/dist/components/commonSetUp/approval/ConditionRow.d.ts +78 -0
- package/dist/components/commonSetUp/approval/DepartmentConditionRow.d.ts +22 -0
- package/dist/components/commonSetUp/approval/FallbackEngineBanner.d.ts +28 -0
- package/dist/components/commonSetUp/approval/FormSection.d.ts +26 -0
- package/dist/components/commonSetUp/approval/IgnoreOverlapModal.d.ts +22 -0
- package/dist/components/commonSetUp/approval/OperatorIsOrIsNotPicker.d.ts +23 -0
- package/dist/components/commonSetUp/approval/RuleOverlapBanner.d.ts +61 -0
- package/dist/components/commonSetUp/approval/RuleOverlapCard.d.ts +31 -0
- package/dist/components/commonSetUp/approval/Switch.d.ts +23 -0
- package/dist/components/commonSetUp/approval/VendorConditionRow.d.ts +27 -0
- package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRuleDetailPage.d.ts +107 -12
- package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRuleDetailPageV1.d.ts +37 -0
- package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRulesPage.d.ts +18 -1
- package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRulesPageV1.d.ts +10 -0
- package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRuleDetailPage.d.ts +100 -12
- package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRuleDetailPageV1.d.ts +37 -0
- package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRulesPage.d.ts +16 -1
- package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRulesPageV1.d.ts +10 -0
- package/dist/components/taskManagement/TaskDetailPage.d.ts +2 -6
- package/dist/components/taskManagement/TaskListRow.d.ts +2 -7
- package/dist/components/taskManagement/TaskListRowSmall.d.ts +1 -3
- package/dist/components/taskManagement/TaskManagementPage.d.ts +28 -4
- package/dist/components/taskManagement/taskManagementFormConstants.d.ts +0 -1
- package/dist/components/taskManagement/taskManagementHeaderItemsData.d.ts +0 -1
- package/dist/context/featureProvider/DynamicConfigNameConstants.d.ts +2 -0
- package/dist/context/featureProvider/useApprovalRulesV3Config.d.ts +31 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.esm.js +322 -317
- package/dist/strings/strings.d.ts +115 -10
- package/package.json +2 -2
- package/dist/components/taskManagement/SubtaskCreationForm.d.ts +0 -14
- package/dist/components/taskManagement/TaskDetailSubtaskForm.d.ts +0 -14
- package/dist/components/taskManagement/taskManagementTypes.d.ts +0 -33
- package/dist/components/taskManagement/taskManagementUtils.d.ts +0 -2
|
@@ -13,9 +13,8 @@ export interface Props {
|
|
|
13
13
|
dateFormat?: string;
|
|
14
14
|
inputStyles?: InputStyles;
|
|
15
15
|
minDate?: ZeniDate;
|
|
16
|
-
placeHolder?: JSX.Element;
|
|
17
16
|
registerOptions?: RegisterOptions;
|
|
18
17
|
style?: React.CSSProperties;
|
|
19
18
|
}
|
|
20
|
-
declare const ZeniDatePickerField: ({ name, defaultValue, registerOptions, dateFormat, style, inputStyles, minDate,
|
|
19
|
+
declare const ZeniDatePickerField: ({ name, defaultValue, registerOptions, dateFormat, style, inputStyles, minDate, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
21
20
|
export default ZeniDatePickerField;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form-state keys used by the amount-condition group.
|
|
3
|
+
*
|
|
4
|
+
* The row is a composite: a comparator picker + one or two amount inputs.
|
|
5
|
+
* All three pieces nest under the single form key `amountCriteria` so the
|
|
6
|
+
* connector can read `formData.amountCriteria` as a complete
|
|
7
|
+
* `AmountCriteria` value at save time.
|
|
8
|
+
*/
|
|
9
|
+
export declare const AMOUNT_CRITERIA_FIELD = "amountCriteria";
|
|
10
|
+
export declare const AMOUNT_COMPARATOR_FIELD = "amountCriteria.comparator";
|
|
11
|
+
export declare const AMOUNT_MIN_FIELD = "amountCriteria.min.amount";
|
|
12
|
+
export declare const AMOUNT_MAX_FIELD = "amountCriteria.max.amount";
|
|
13
|
+
export interface AmountConditionRowProps {
|
|
14
|
+
/**
|
|
15
|
+
* Currency symbol surfaced as a placeholder prefix on every amount input.
|
|
16
|
+
* Defaults to `"$"` when the rule has no stored currency yet.
|
|
17
|
+
*/
|
|
18
|
+
currencySymbol?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function AmountConditionRow({ currencySymbol, }: AmountConditionRowProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export default AmountConditionRow;
|
|
@@ -1,14 +1,81 @@
|
|
|
1
1
|
import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* The setup-approver view selectors alias the same underlying
|
|
4
|
+
* `ApprovalRuleWithUser` shape across bills and reimbursements.
|
|
5
|
+
*/
|
|
6
|
+
export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
|
|
2
7
|
export interface DialogAction {
|
|
3
8
|
onCancelClick: () => void;
|
|
4
9
|
onOkClick: (notes?: string) => void;
|
|
5
10
|
}
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
/**
|
|
12
|
+
* react-dnd item shape carried while dragging a rule card. Carries
|
|
13
|
+
* the source rule's id so the drop target can issue an
|
|
14
|
+
* 'onReorder(sourceId, targetId)' callback to the parent on release.
|
|
15
|
+
*/
|
|
16
|
+
export interface RuleDragItem {
|
|
17
|
+
ruleId: string;
|
|
18
|
+
}
|
|
19
|
+
/** react-dnd type discriminator for approval-rule cards. */
|
|
20
|
+
export declare const APPROVAL_RULE_DND_TYPE = "approval-rule";
|
|
21
|
+
export interface Props {
|
|
22
|
+
approvalRule: ApprovalRuleWithUser;
|
|
8
23
|
isLastSection: boolean;
|
|
9
24
|
showDeleteBtn: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Optional department-id → display-name map. In this codebase
|
|
27
|
+
* "department" maps to the Class entity (accounting class); the list
|
|
28
|
+
* page derives this from `state.classState`.
|
|
29
|
+
*/
|
|
30
|
+
departmentNamesById?: Record<string, string>;
|
|
10
31
|
disableButtons?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Number rendered before the rule name (e.g. "1. Marketing vendor block").
|
|
34
|
+
* Defaults to `approvalRule.priority`.
|
|
35
|
+
*/
|
|
36
|
+
positionNumber?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Optional vendor-id → display-name map. The list page derives this
|
|
39
|
+
* from `state.contactState` (vendors are stored as contacts). Chips
|
|
40
|
+
* fall back to the raw ID when no entry is found.
|
|
41
|
+
*/
|
|
42
|
+
vendorNamesById?: Record<string, string>;
|
|
11
43
|
onDeleteRuleClick: (ruleId: string) => void;
|
|
12
44
|
onEditRuleClick: (ruleId?: string) => void;
|
|
13
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Called when the user drops THIS card (drop target) after dragging
|
|
47
|
+
* another rule onto it. Receives the source and target rule ids;
|
|
48
|
+
* the list page composes the new order and dispatches the reorder
|
|
49
|
+
* action. Optional — when omitted the card renders without a drag
|
|
50
|
+
* handle and is not draggable.
|
|
51
|
+
*/
|
|
52
|
+
onReorderRules?: (dragRuleId: string, hoverRuleId: string) => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Approval rule list-page card per Approval Rules 3.0:
|
|
56
|
+
*
|
|
57
|
+
* ┌─────────────────────────────────────────────────────────┐
|
|
58
|
+
* │ 1. Marketing vendor block [Separation of Duties] ⋮│
|
|
59
|
+
* │ All marketing bills route through department lead │
|
|
60
|
+
* │ When: [Amount > $1,000] [Department is Sales & Mktg] │
|
|
61
|
+
* │ Then: 1. Require approval from Jordan Leo or Elena King │
|
|
62
|
+
* │ 2. Require approval from Matteo Ramsey │
|
|
63
|
+
* └─────────────────────────────────────────────────────────┘
|
|
64
|
+
*
|
|
65
|
+
* Accepts the entity-shape `ApprovalRuleWithUser` (steps have resolved
|
|
66
|
+
* User objects, criteria is the discriminated union). The parent
|
|
67
|
+
* provides optional `vendorNamesById` / `departmentNamesById` so chips
|
|
68
|
+
* render names instead of raw IDs.
|
|
69
|
+
*
|
|
70
|
+
* The kebab now opens an internal dropdown (Edit / Delete for V1; Pause
|
|
71
|
+
* and Activity to follow once their action wiring exists). Edit dispatches
|
|
72
|
+
* `onEditRuleClick(approvalRuleId)`; Delete opens the legacy delete-
|
|
73
|
+
* confirmation popup which then dispatches `onDeleteRuleClick(approvalRuleId)`.
|
|
74
|
+
*
|
|
75
|
+
* `showDeleteBtn` is accepted for backward compat with the existing list
|
|
76
|
+
* pages but no longer drives any UI — the kebab and its menu items are
|
|
77
|
+
* always rendered (subject to `disableButtons` for the in-flight pusher
|
|
78
|
+
* case). Once callers stop passing it, the prop can be removed.
|
|
79
|
+
*/
|
|
80
|
+
declare const ApprovalRuleSection: ({ approvalRule, isLastSection, disableButtons, onDeleteRuleClick, onEditRuleClick, vendorNamesById, departmentNamesById, positionNumber, onReorderRules, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
14
81
|
export default ApprovalRuleSection;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
|
|
2
|
+
export interface DialogAction {
|
|
3
|
+
onCancelClick: () => void;
|
|
4
|
+
onOkClick: (notes?: string) => void;
|
|
5
|
+
}
|
|
6
|
+
declare const ApprovalRuleSection: ({ showDeleteBtn, disableButtons, isLastSection, approvalRule, onEditRuleClick, onDeleteRuleClick, }: {
|
|
7
|
+
approvalRule: BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
|
|
8
|
+
isLastSection: boolean;
|
|
9
|
+
showDeleteBtn: boolean;
|
|
10
|
+
disableButtons?: boolean;
|
|
11
|
+
onDeleteRuleClick: (ruleId: string) => void;
|
|
12
|
+
onEditRuleClick: (ruleId?: string) => void;
|
|
13
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default ApprovalRuleSection;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ApprovalActionType, AttributeType, User } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* Approval Rules 3.0 — Set Approval Stages row.
|
|
4
|
+
*
|
|
5
|
+
* One stage in the rule's sequential approval pipeline, laid out as:
|
|
6
|
+
*
|
|
7
|
+
* [::] [N.] [Require | Notify] [Actor kind ▾] [Value picker] [🗑]
|
|
8
|
+
*
|
|
9
|
+
* Actor kind drives the value picker:
|
|
10
|
+
* - "specific_person" → user multi-select (renders avatars + "or"
|
|
11
|
+
* between names, via the existing `UserMultiSelectField`).
|
|
12
|
+
* - "role" → single-select of `Manager / Manager of Manager /
|
|
13
|
+
* Vendor Owner`, backed by `AttributeType` in `client-epic-state`.
|
|
14
|
+
*
|
|
15
|
+
* Form-state model — each row binds to a slot under `steps[N]`:
|
|
16
|
+
* - `steps[N].action` → 'require_approval' | 'send_notification'
|
|
17
|
+
* - `steps[N].actorKind` → 'specific_person' | 'role'
|
|
18
|
+
* - `steps[N].persons` → `{allUsers, allNonUsers, selectedUsers, selectedNonUsers}`
|
|
19
|
+
* (the UserMultiSelectField-native shape)
|
|
20
|
+
* - `steps[N].selectedRole` → AttributeType | undefined
|
|
21
|
+
*
|
|
22
|
+
* Both `persons` and `selectedRole` live on the slot at all times so
|
|
23
|
+
* the user can toggle actor kind without losing the data they entered
|
|
24
|
+
* for the other variant. The screen connector reads the relevant
|
|
25
|
+
* branch based on `actorKind` at save time and ignores the other.
|
|
26
|
+
*
|
|
27
|
+
* Drag handle is wired up to 'react-dnd' (HTML5 backend, configured
|
|
28
|
+
* by the enclosing ApprovalStagesSection's DndProvider). The handle
|
|
29
|
+
* is the drag source; the whole row is the drop target with the
|
|
30
|
+
* standard hover-middle gate so a drag past the row's vertical center
|
|
31
|
+
* triggers reorder. The parent owns the reorder via the
|
|
32
|
+
* 'onReorder(dragIndex, hoverIndex)' callback — the row never mutates
|
|
33
|
+
* form state directly. See ApprovalsActivity / RealTimeApprovalListItem
|
|
34
|
+
* for the canonical pattern this mirrors.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* react-dnd item shape carried while dragging a stage row. Index is
|
|
38
|
+
* mutated in-place during hover (per the react-dnd reorder pattern)
|
|
39
|
+
* so subsequent hovers see the rebased index without re-querying the
|
|
40
|
+
* monitor.
|
|
41
|
+
*/
|
|
42
|
+
export interface StageDragItem {
|
|
43
|
+
index: number;
|
|
44
|
+
}
|
|
45
|
+
/** react-dnd type discriminator for stage rows. */
|
|
46
|
+
export declare const STAGE_DND_TYPE = "approval-stage";
|
|
47
|
+
/** The two actor-kind variants the row's type dropdown surfaces. */
|
|
48
|
+
export type ApprovalStageActorKind = "specific_person" | "role";
|
|
49
|
+
/**
|
|
50
|
+
* Form-state shape for a single stage row. Lives on
|
|
51
|
+
* `FormData.steps[N]` in the BillPay and Reimbursement detail pages.
|
|
52
|
+
*
|
|
53
|
+
* `persons` and `selectedRole` both live on every stage so the user
|
|
54
|
+
* can toggle actor kind without losing data they entered for the
|
|
55
|
+
* other variant. The screen connector reads only the branch that
|
|
56
|
+
* matches `actorKind` at save time.
|
|
57
|
+
*/
|
|
58
|
+
export interface ApprovalStageData {
|
|
59
|
+
/** Sequential index within the stage list. Re-numbered on add/remove. */
|
|
60
|
+
stageIndex: number;
|
|
61
|
+
/**
|
|
62
|
+
* Require / Notify segmented toggle binding. Bare string because
|
|
63
|
+
* the toggle uses a plain `Controller` (not `SingleSelectField`).
|
|
64
|
+
*/
|
|
65
|
+
action?: ApprovalActionType;
|
|
66
|
+
/**
|
|
67
|
+
* Drives the value picker variant. Wrapped because the dropdown is
|
|
68
|
+
* `SingleSelectField`-driven (writes `{allOptions, selectedOption}`).
|
|
69
|
+
* Readers do `actorKind.selectedOption`.
|
|
70
|
+
*/
|
|
71
|
+
actorKind?: {
|
|
72
|
+
allOptions: ApprovalStageActorKind[];
|
|
73
|
+
selectedOption?: ApprovalStageActorKind;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Bound when `actorKind.selectedOption === "specific_person"`.
|
|
77
|
+
* Shape matches `UserMultiSelectField`'s native value so the field
|
|
78
|
+
* can re-use existing avatar rendering and "or" join.
|
|
79
|
+
*/
|
|
80
|
+
persons?: {
|
|
81
|
+
allNonUsers: any[];
|
|
82
|
+
allUsers: any[];
|
|
83
|
+
selectedNonUsers: any[];
|
|
84
|
+
selectedUsers: any[];
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Bound when `actorKind.selectedOption === "role"`. Wrapped shape
|
|
88
|
+
* (same reason as actorKind). Readers do `selectedRole.selectedOption`.
|
|
89
|
+
*/
|
|
90
|
+
selectedRole?: {
|
|
91
|
+
allOptions: AttributeType[];
|
|
92
|
+
selectedOption?: AttributeType;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export interface ApprovalStageRowProps {
|
|
96
|
+
/** Pool of users surfaced by the "Specific Person" multi-select. */
|
|
97
|
+
allUsers: User[];
|
|
98
|
+
/** When `false`, the trash icon is dimmed and inert. */
|
|
99
|
+
canRemove: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Base react-hook-form path for this row (e.g. `"steps.0"`). Inner
|
|
102
|
+
* controls suffix `.action`, `.actorKind`, `.persons`,
|
|
103
|
+
* `.selectedRole` as needed. The shape mirrors `ApprovalStageData`
|
|
104
|
+
* defined alongside the parent section.
|
|
105
|
+
*/
|
|
106
|
+
fieldNameBase: string;
|
|
107
|
+
/** Zero-based index of this row within the parent's stage list. */
|
|
108
|
+
index: number;
|
|
109
|
+
/** Called when the user clicks the trash icon. */
|
|
110
|
+
onRemove: () => void;
|
|
111
|
+
/**
|
|
112
|
+
* Called continuously while the user drags one stage over another,
|
|
113
|
+
* once the cursor crosses the hover target's vertical midpoint.
|
|
114
|
+
* Optional — when omitted the row is rendered as inert (no drag
|
|
115
|
+
* handlers attached). The parent owns the reorder mutation; this
|
|
116
|
+
* callback receives the two indices to swap.
|
|
117
|
+
*/
|
|
118
|
+
onReorder?: (dragIndex: number, hoverIndex: number) => void;
|
|
119
|
+
}
|
|
120
|
+
export declare function ApprovalStageRow({ index, fieldNameBase, allUsers, onRemove, canRemove, onReorder, }: ApprovalStageRowProps): import("react/jsx-runtime").JSX.Element;
|
|
121
|
+
export default ApprovalStageRow;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { User } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* Approval Rules 3.0 — Set Approval Stages form section.
|
|
4
|
+
*
|
|
5
|
+
* Renders the third FormSection of the rule create/edit form. Holds:
|
|
6
|
+
*
|
|
7
|
+
* ┌────────────────────────────────────────────────────────────┐
|
|
8
|
+
* │ 1. [Require|Notify] [Specific Person ▾] [users…] [🗑] │
|
|
9
|
+
* │ 2. [Require|Notify] [Role ▾] [Manager ▾] [🗑] │
|
|
10
|
+
* │ Clear All ⊕ Add Approval Stage │
|
|
11
|
+
* │ ───────────────────────────────────────────────────────── │
|
|
12
|
+
* │ Separation of Duties ⏺ │
|
|
13
|
+
* │ Enabling separation of duties prevent ... │
|
|
14
|
+
* └────────────────────────────────────────────────────────────┘
|
|
15
|
+
*
|
|
16
|
+
* Stage rows are owned by `formData.steps`. The component reads the
|
|
17
|
+
* list length from form state via `useWatch` indirectly through the
|
|
18
|
+
* stagesValue prop, and lets the parent own the add / remove / clear
|
|
19
|
+
* actions (mirroring the ConditionRow pattern). The parent is also
|
|
20
|
+
* responsible for translating the form-data shape to canonical
|
|
21
|
+
* `Step[]` at save time in the screen connector.
|
|
22
|
+
*
|
|
23
|
+
* The Separation of Duties toggle sits inside the same FormSection
|
|
24
|
+
* card per product spec — SoD is a stage-modifier, so visually it
|
|
25
|
+
* belongs with the stages it modifies.
|
|
26
|
+
*/
|
|
27
|
+
export interface ApprovalStagesSectionProps {
|
|
28
|
+
/**
|
|
29
|
+
* Pool of users surfaced inside the "Specific Person" multi-select
|
|
30
|
+
* on each row. Resolved by the parent — in production, this is the
|
|
31
|
+
* tenant's filtered approver list.
|
|
32
|
+
*/
|
|
33
|
+
allUsers: User[];
|
|
34
|
+
/** Form-state key for the SoD boolean toggle. */
|
|
35
|
+
separationOfDutiesFieldName: string;
|
|
36
|
+
/**
|
|
37
|
+
* Stage 'fields' produced by 'useFieldArray' in the parent. Each
|
|
38
|
+
* carries a stable 'id' the section uses as the React key so React
|
|
39
|
+
* physically reorders DOM nodes on drag-drop — which in turn
|
|
40
|
+
* forces each row's 'index' / 'fieldNameBase' props to update and
|
|
41
|
+
* its Controllers to re-bind to the new form-state paths. Keying
|
|
42
|
+
* by index instead silently broke drag-and-drop because the
|
|
43
|
+
* positionally-keyed rows kept stale Controller bindings.
|
|
44
|
+
*/
|
|
45
|
+
stageFields: ReadonlyArray<{
|
|
46
|
+
id: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Form-state key prefix for stage rows — typically `"steps"`. Each
|
|
50
|
+
* row's full path is `${stagesFieldName}.${index}`.
|
|
51
|
+
*/
|
|
52
|
+
stagesFieldName: string;
|
|
53
|
+
onAddStage: () => void;
|
|
54
|
+
onClearAllStages: () => void;
|
|
55
|
+
onRemoveStage: (index: number) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Called when the user drops a dragged stage row onto another row.
|
|
58
|
+
* The parent re-orders the form-state 'steps' array so the new
|
|
59
|
+
* order propagates to the save payload via the existing
|
|
60
|
+
* 'createSteps' iteration. Optional — when omitted the rows render
|
|
61
|
+
* without drag handlers attached (handle stays visible but inert).
|
|
62
|
+
*/
|
|
63
|
+
onReorderStages?: (dragIndex: number, hoverIndex: number) => void;
|
|
64
|
+
}
|
|
65
|
+
export declare function ApprovalStagesSection({ allUsers, stageFields, stagesFieldName, separationOfDutiesFieldName, onAddStage, onClearAllStages, onRemoveStage, onReorderStages, }: ApprovalStagesSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
66
|
+
export default ApprovalStagesSection;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ConditionType } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* `ConditionType` is re-exported here so existing import sites in
|
|
4
|
+
* `web-components` (BillPay + Reimbursement detail pages, stories)
|
|
5
|
+
* keep working unchanged. The canonical definition lives in
|
|
6
|
+
* `client-epic-state` (derived from `Criteria["type"]`) so the UI
|
|
7
|
+
* discriminator can't drift from the data model.
|
|
8
|
+
*/
|
|
9
|
+
export type { ConditionType };
|
|
10
|
+
/**
|
|
11
|
+
* Approval Rules 3.0 — unified condition row.
|
|
12
|
+
*
|
|
13
|
+
* A single row in the Set Conditions section, laid out as one
|
|
14
|
+
* horizontal line:
|
|
15
|
+
*
|
|
16
|
+
* [ Type ▾ ] [ Operator/Comparator ] [ Value(s) ] [ 🗑 ]
|
|
17
|
+
*
|
|
18
|
+
* For Amount: operator slot holds the comparator dropdown
|
|
19
|
+
* (Greater than / Less than / Between), and the value slot is one
|
|
20
|
+
* number input (or two for "Between"). For Vendor / Department: the
|
|
21
|
+
* operator slot is a segmented `is` / `is not` toggle, and the value
|
|
22
|
+
* slot is a multi-select of vendor or department names.
|
|
23
|
+
*
|
|
24
|
+
* Form-state model — controls bind directly to the existing form
|
|
25
|
+
* paths used by the (now-deprecated for screen use) per-variant rows:
|
|
26
|
+
* - `amountCriteria.comparator`, `amountCriteria.min.amount`,
|
|
27
|
+
* `amountCriteria.max.amount`
|
|
28
|
+
* - `vendorCriteria.operator`, `vendorCriteria.selection`
|
|
29
|
+
* - `departmentCriteria.operator`, `departmentCriteria.selection`
|
|
30
|
+
*
|
|
31
|
+
* The "list of conditions" is a *visual* construct owned by the
|
|
32
|
+
* parent: it tracks the ordered list of active types and renders one
|
|
33
|
+
* ConditionRow per type. When a row is removed the parent clears the
|
|
34
|
+
* relevant form slot so the payload mapper drops the condition. The
|
|
35
|
+
* leading type dropdown is parent-controlled (not bound to
|
|
36
|
+
* react-hook-form) because that list is the source of truth.
|
|
37
|
+
*
|
|
38
|
+
* Per task #11 (clear-all UX): the Amount row is non-removable. Its
|
|
39
|
+
* trash icon is rendered but visually dimmed and disabled so the row
|
|
40
|
+
* keeps its horizontal alignment with removable rows.
|
|
41
|
+
*
|
|
42
|
+
* Visual polish (this iteration):
|
|
43
|
+
* 1. Each control sits inside a `ControlCard` styled wrapper that
|
|
44
|
+
* paints the design-system border + background so the raw
|
|
45
|
+
* react-select primitives don't expose their default UA outlines.
|
|
46
|
+
* 2. The `is` / `is_not` operator is a binary segmented toggle
|
|
47
|
+
* (built inline below) rather than a dropdown, matching the
|
|
48
|
+
* target design.
|
|
49
|
+
* 3. The multi-select primitive keeps its built-in
|
|
50
|
+
* focused → chips / blurred → comma-text rendering — changing
|
|
51
|
+
* that requires modifying the shared `MultiSelectField`, which
|
|
52
|
+
* every other consumer depends on. Flagged as a follow-up.
|
|
53
|
+
*/
|
|
54
|
+
export interface ConditionRowProps {
|
|
55
|
+
availableTypes: readonly ConditionType[];
|
|
56
|
+
/** When `false`, the trash icon is dimmed and inert. */
|
|
57
|
+
canRemove: boolean;
|
|
58
|
+
index: number;
|
|
59
|
+
rowType: ConditionType;
|
|
60
|
+
/**
|
|
61
|
+
* Types currently used by *other* rows (i.e. excludes this row's own
|
|
62
|
+
* type). They are filtered out of the dropdown so the user can't
|
|
63
|
+
* create duplicates.
|
|
64
|
+
*/
|
|
65
|
+
usedTypes: ReadonlySet<ConditionType>;
|
|
66
|
+
/** Department multi-select options + label lookup. */
|
|
67
|
+
allDepartmentIds?: string[];
|
|
68
|
+
/** Vendor multi-select options + label lookup. */
|
|
69
|
+
allVendorIds?: string[];
|
|
70
|
+
/** Forwarded to the amount value input when `rowType === "amount"`. */
|
|
71
|
+
currencySymbol?: string;
|
|
72
|
+
departmentNamesById?: Record<string, string>;
|
|
73
|
+
vendorNamesById?: Record<string, string>;
|
|
74
|
+
onRemove: () => void;
|
|
75
|
+
onTypeChange: (next: ConditionType) => void;
|
|
76
|
+
}
|
|
77
|
+
export declare function ConditionRow({ rowType, index, availableTypes, usedTypes, onTypeChange, onRemove, canRemove, currencySymbol, allVendorIds, vendorNamesById, allDepartmentIds, departmentNamesById, }: ConditionRowProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
export default ConditionRow;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form-state keys used by the department condition group.
|
|
3
|
+
*
|
|
4
|
+
* The form-side split (operator + selection multi-select) mirrors
|
|
5
|
+
* VendorConditionRow. The screen connector reads
|
|
6
|
+
* `selection.selectedOptions` and translates to the canonical
|
|
7
|
+
* `DepartmentCriteria.departmentIds` at save time.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEPARTMENT_CRITERIA_FIELD = "departmentCriteria";
|
|
10
|
+
export declare const DEPARTMENT_OPERATOR_FIELD = "departmentCriteria.operator";
|
|
11
|
+
export declare const DEPARTMENT_SELECTION_FIELD = "departmentCriteria.selection";
|
|
12
|
+
export interface DepartmentConditionRowProps {
|
|
13
|
+
/**
|
|
14
|
+
* All department IDs the user can choose from. Display names are
|
|
15
|
+
* resolved via `departmentNamesById`. In this codebase "department"
|
|
16
|
+
* maps to the Class entity, so this is `classId` for each Class.
|
|
17
|
+
*/
|
|
18
|
+
allDepartmentIds: string[];
|
|
19
|
+
departmentNamesById: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export declare function DepartmentConditionRow({ allDepartmentIds, departmentNamesById, }: DepartmentConditionRowProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default DepartmentConditionRow;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* Shared shape across the two product-specific selectors. Same alias used
|
|
4
|
+
* in ApprovalRuleSection.
|
|
5
|
+
*/
|
|
6
|
+
export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
|
|
7
|
+
export interface FallbackEngineBannerProps {
|
|
8
|
+
/**
|
|
9
|
+
* The explicit fallback rule for this list, if the tenant has configured
|
|
10
|
+
* one (i.e. `approvalRule.isFallback === true`). When undefined, the
|
|
11
|
+
* banner renders a placeholder approver list derived from the default
|
|
12
|
+
* non-user actor labels. Final copy for the default case is still TBD;
|
|
13
|
+
* we use existing locale strings for now and swap when product confirms.
|
|
14
|
+
*/
|
|
15
|
+
fallbackRule?: ApprovalRuleWithUser;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Top-of-list-page banner that surfaces which approvers will be requested
|
|
19
|
+
* when no other approval rule matches a bill / reimbursement.
|
|
20
|
+
*
|
|
21
|
+
* Per Rubal's feedback in the handoff call, the approver list is rendered
|
|
22
|
+
* as a flat "Vendor Owner or Manager or Admin" listing — replacing the
|
|
23
|
+
* old arrow-flow format. Both branches (explicit fallback rule vs.
|
|
24
|
+
* default trio) render through the same actor-list path so the styling
|
|
25
|
+
* stays consistent.
|
|
26
|
+
*/
|
|
27
|
+
declare const FallbackEngineBanner: ({ fallbackRule }: FallbackEngineBannerProps) => import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export default FallbackEngineBanner;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ResponsiveSized } from '../../../context/windowSizeProvider';
|
|
2
|
+
/**
|
|
3
|
+
* A labelled section wrapper for the approval-rule create/edit form.
|
|
4
|
+
*
|
|
5
|
+
* Renders a bold heading + lighter subheading above a bordered card
|
|
6
|
+
* holding the section's controls. Used to break the form into
|
|
7
|
+
* "Add Rule", "Set Conditions", and "Set Approval Stages" groups so
|
|
8
|
+
* each chunk of the rule is visually separated.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Layout constants for the create / edit approval-rule form column.
|
|
12
|
+
*
|
|
13
|
+
* Exported so other components sharing the column (e.g. the overlap
|
|
14
|
+
* warning banner that sits above the FormSections) can match the same
|
|
15
|
+
* responsive width and stay in vertical alignment with the cards.
|
|
16
|
+
*/
|
|
17
|
+
export declare const D: {
|
|
18
|
+
width: ResponsiveSized;
|
|
19
|
+
};
|
|
20
|
+
export interface FormSectionProps {
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
heading: string;
|
|
23
|
+
subheading: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function FormSection({ heading, subheading, children }: FormSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export default FormSection;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval Rules 3.0 — "Proceed with overlapping rules?" confirmation.
|
|
3
|
+
*
|
|
4
|
+
* Mounted by the BillPay / Reimbursement detail page when the user
|
|
5
|
+
* clicks "Ignore & Proceed" in RuleOverlapBanner. Cancel returns to
|
|
6
|
+
* the form with no side effects (banner remains visible); Proceed
|
|
7
|
+
* dispatches the underlying save. This is the second-stage gate on
|
|
8
|
+
* top of the banner itself — once the user acknowledges the overlap,
|
|
9
|
+
* the rule is created / updated as-is.
|
|
10
|
+
*
|
|
11
|
+
* Thin wrapper over the shared ConfirmationPopup, kept as a named
|
|
12
|
+
* file so the wiring side reads naturally and so the copy lives in
|
|
13
|
+
* one place.
|
|
14
|
+
*/
|
|
15
|
+
export interface IgnoreOverlapModalProps {
|
|
16
|
+
/** True while the underlying save dispatch is in flight. */
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
onCancel: () => void;
|
|
19
|
+
onProceed: () => void;
|
|
20
|
+
}
|
|
21
|
+
declare const IgnoreOverlapModal: ({ onCancel, onProceed, isLoading, }: IgnoreOverlapModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default IgnoreOverlapModal;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `is` / `is_not` operator used by both vendor and department
|
|
3
|
+
* condition rows. Extracted so the option list, locale labels, and
|
|
4
|
+
* binding shape stay identical between rows.
|
|
5
|
+
*/
|
|
6
|
+
export type IsOrIsNotOperator = "is" | "is_not";
|
|
7
|
+
export interface OperatorIsOrIsNotPickerProps {
|
|
8
|
+
/**
|
|
9
|
+
* The label rendered to the left of the picker (e.g. "Vendor"
|
|
10
|
+
* or "Department"). Each row chooses its own copy so the picker
|
|
11
|
+
* row reads naturally as "Vendor is …" / "Department is not …".
|
|
12
|
+
*/
|
|
13
|
+
label: string;
|
|
14
|
+
/**
|
|
15
|
+
* Full react-hook-form path to the operator value. Typical values:
|
|
16
|
+
* - `vendorCriteria.operator`
|
|
17
|
+
* - `departmentCriteria.operator`
|
|
18
|
+
*/
|
|
19
|
+
name: string;
|
|
20
|
+
defaultOperator?: IsOrIsNotOperator;
|
|
21
|
+
}
|
|
22
|
+
export declare function OperatorIsOrIsNotPicker({ label, name, defaultOperator, }: OperatorIsOrIsNotPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default OperatorIsOrIsNotPicker;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { RuleOverlap } from '@zeniai/client-epic-state';
|
|
2
|
+
import { ApprovalRuleWithUser } from './RuleOverlapCard';
|
|
3
|
+
/**
|
|
4
|
+
* Approval Rules 3.0 — frontend overlap warning surface.
|
|
5
|
+
*
|
|
6
|
+
* Sits above the Add Rule / detail form when 'detectRuleOverlap'
|
|
7
|
+
* returns a non-empty list. Outer width matches the form column
|
|
8
|
+
* (same 'FormSection.D.width' tuple) so the banner stacks cleanly
|
|
9
|
+
* above the first SectionCard.
|
|
10
|
+
*
|
|
11
|
+
* Structure (per design):
|
|
12
|
+
* ┌─[gold border]──────────────────────────────────────┐
|
|
13
|
+
* │ [warm warning fill — header only] │
|
|
14
|
+
* │ ⚠ Partial rule overlap detected │
|
|
15
|
+
* │ Conditions partially overlap with… │
|
|
16
|
+
* ├────────────────────────────────────────────────────┤
|
|
17
|
+
* │ [grey-5 surface — body] │
|
|
18
|
+
* │ ┌─ inner rule card ───────────────────────────┐ │
|
|
19
|
+
* │ │ Rule name [SoD][Set at Priority] │ │
|
|
20
|
+
* │ │ Description │ │
|
|
21
|
+
* │ │ When: [chip] [chip] │ │
|
|
22
|
+
* │ │ Then: 1. Require approval from … │ │
|
|
23
|
+
* │ └─────────────────────────────────────────────┘ │
|
|
24
|
+
* │ [Ignore & Proceed] [Edit] │
|
|
25
|
+
* └────────────────────────────────────────────────────┘
|
|
26
|
+
*
|
|
27
|
+
* Colors are explicit static tokens per the design (not theme-
|
|
28
|
+
* adaptive) — the warning surface stays warm-amber in both themes,
|
|
29
|
+
* the body stays light, the rule card stays white. See the styled
|
|
30
|
+
* components below for the token-by-token mapping.
|
|
31
|
+
*
|
|
32
|
+
* Action buttons sit at the bottom-right of the body. 'Ignore &
|
|
33
|
+
* Proceed' fires the parent's save flow as-is. 'Edit Existing Rule'
|
|
34
|
+
* navigates same-tab to the conflicting rule's detail page; when
|
|
35
|
+
* multiple overlaps are present we suppress this button because it
|
|
36
|
+
* has no unambiguous target — the user can pick a card via its own
|
|
37
|
+
* header context (TODO: multi-overlap design pass).
|
|
38
|
+
*/
|
|
39
|
+
export interface RuleOverlapBannerProps {
|
|
40
|
+
overlaps: RuleOverlap<ApprovalRuleWithUser>[];
|
|
41
|
+
departmentNamesById?: Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Disables both action buttons while the page is in an in-flight
|
|
44
|
+
* save (so the user can't double-fire or navigate away mid-write).
|
|
45
|
+
*/
|
|
46
|
+
disableButtons?: boolean;
|
|
47
|
+
vendorNamesById?: Record<string, string>;
|
|
48
|
+
/**
|
|
49
|
+
* Called when the user clicks Edit Existing Rule. The parent's
|
|
50
|
+
* connector navigates same-tab to that rule's edit page. Only
|
|
51
|
+
* invoked when 'overlaps.length === 1'.
|
|
52
|
+
*/
|
|
53
|
+
onEditExistingRule: (ruleId: string) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Called when the user accepts the overlap and wants the save to
|
|
56
|
+
* proceed. The parent dispatches the underlying save here.
|
|
57
|
+
*/
|
|
58
|
+
onIgnoreAndProceed: () => void;
|
|
59
|
+
}
|
|
60
|
+
declare const RuleOverlapBanner: ({ overlaps, vendorNamesById, departmentNamesById, onIgnoreAndProceed, onEditExistingRule, disableButtons, }: RuleOverlapBannerProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
61
|
+
export default RuleOverlapBanner;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
|
|
2
|
+
/**
|
|
3
|
+
* Shared shape across the two product-specific selectors. Same alias
|
|
4
|
+
* used in ApprovalRuleSection / FallbackEngineBanner. We accept the
|
|
5
|
+
* full `WithUser` shape (not just a structural subset) because the
|
|
6
|
+
* card renders steps with resolved user names.
|
|
7
|
+
*/
|
|
8
|
+
export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
|
|
9
|
+
/**
|
|
10
|
+
* Approval Rules 3.0 — per-rule overlap row inside RuleOverlapBanner.
|
|
11
|
+
*
|
|
12
|
+
* Renders the conflicting rule almost identically to the list-page
|
|
13
|
+
* card (ApprovalRuleSection): name + Priority pill + optional SoD
|
|
14
|
+
* pill on the right, description below, then 'When:' chips and
|
|
15
|
+
* 'Then:' step list. The kebab + edit/delete actions are intentionally
|
|
16
|
+
* omitted — the Edit Existing Rule CTA lives at the banner level and
|
|
17
|
+
* acts on the rule that this card represents.
|
|
18
|
+
*
|
|
19
|
+
* The chip / step rendering is duplicated from ApprovalRuleSection
|
|
20
|
+
* rather than extracted to a shared file: the two surfaces have
|
|
21
|
+
* different surrounding chrome and the helpers are small. If a third
|
|
22
|
+
* consumer ever needs them, extract at that point.
|
|
23
|
+
*/
|
|
24
|
+
export interface RuleOverlapCardProps {
|
|
25
|
+
departmentNamesById: Record<string, string>;
|
|
26
|
+
rule: ApprovalRuleWithUser;
|
|
27
|
+
vendorNamesById: Record<string, string>;
|
|
28
|
+
dataTestId?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const RuleOverlapCard: ({ rule, vendorNamesById, departmentNamesById, dataTestId, }: RuleOverlapCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export default RuleOverlapCard;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval Rules 3.0 — boolean toggle primitive.
|
|
3
|
+
*
|
|
4
|
+
* Inline iOS-style switch built locally rather than pulling in a new
|
|
5
|
+
* dependency, because (a) the project does not export a Switch /
|
|
6
|
+
* Toggle field, and (b) the two current consumers (the Separation of
|
|
7
|
+
* Duties toggle inside Set Approval Stages, and the "Set as default
|
|
8
|
+
* fallback" toggle inside Add Rule) want the same shape.
|
|
9
|
+
*
|
|
10
|
+
* The control writes a bare boolean to form state under the supplied
|
|
11
|
+
* field name — no {allOptions, selectedOption} wrapping like the
|
|
12
|
+
* shared SingleSelectField. That matches the canonical shape of
|
|
13
|
+
* boolean form slots like isFallback and separationOfDuties so the
|
|
14
|
+
* screen connector reads them directly without normalisation.
|
|
15
|
+
*/
|
|
16
|
+
export interface SwitchProps {
|
|
17
|
+
/** react-hook-form field path (e.g. "isFallback" or "separationOfDuties"). */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Optional starting value. Defaults to false. */
|
|
20
|
+
defaultValue?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function Switch({ name, defaultValue }: SwitchProps): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default Switch;
|