Skip to content

Commit 34c6eb6

Browse files
authored
feat: Expiry rule now has a notice if not included in the permission (#278)
* Expiry rule now has a notice if not included in the permission - Rules can now define a contentWhenDisabled that will be shown if the rule is removed - Expiry rule for all permission types includes a notice that you should probably add an expiry * contentWhenDisabled is now a function so that we can depend on the translate function to be initialised * Switch notice to warning style (orange)
1 parent 48819c6 commit 34c6eb6

File tree

10 files changed

+182
-116
lines changed

10 files changed

+182
-116
lines changed

packages/gator-permissions-snap/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
"expiryTooltip": {
6565
"message": "The expiry date of the permission"
6666
},
67+
"expiryContentWhenDisabled": {
68+
"message": "Never expires - we recommend that you set an expiry."
69+
},
6770
"streamAmountLabel": {
6871
"message": "Stream Amount"
6972
},

packages/gator-permissions-snap/src/core/rules.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function renderRule<
3232
context: TContext;
3333
metadata: TMetadata;
3434
}): SnapElement | null {
35-
const { label, type, name, isOptional } = rule;
35+
const { label, type, name, isOptional, contentWhenDisabled } = rule;
3636
const {
3737
value,
3838
error,
@@ -68,6 +68,7 @@ export function renderRule<
6868
addFieldButtonName={addFieldButtonName}
6969
removeFieldButtonName={removeFieldButtonName}
7070
iconData={iconData}
71+
contentWhenDisabled={contentWhenDisabled}
7172
/>
7273
);
7374
}
@@ -104,6 +105,7 @@ export function renderRule<
104105
allowPastDate={allowPastDate}
105106
removeFieldButtonName={removeFieldButtonName}
106107
addFieldButtonName={addFieldButtonName}
108+
contentWhenDisabled={contentWhenDisabled}
107109
/>
108110
);
109111
}

packages/gator-permissions-snap/src/core/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ export type RuleDefinition<
218218
getRuleData: (config: { context: TContext; metadata: TMetadata }) => RuleData;
219219
// todo: it would be nice if we could make the value type more specific
220220
updateContext: (context: TContext, value: any) => TContext;
221+
/** When provided, called to get content shown when the field is toggled off. */
222+
contentWhenDisabled?: () => string;
221223
};
222224

223225
/**

packages/gator-permissions-snap/src/permissions/rules.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export const createExpiryRule = <
8484
expiry,
8585
};
8686
},
87+
contentWhenDisabled: () => translate('expiryContentWhenDisabled'),
8788
};
8889
};
8990

packages/gator-permissions-snap/src/ui/components/DateTimePickerField.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type DateTimePickerFieldParams = Pick<
1212
| 'isEditable'
1313
| 'removeFieldButtonName'
1414
| 'addFieldButtonName'
15+
| 'contentWhenDisabled'
1516
> & {
1617
name: string;
1718
/** ISO 8601 formatted date string with timezone */
@@ -30,6 +31,7 @@ export const DateTimePickerField = ({
3031
allowPastDate,
3132
addFieldButtonName,
3233
removeFieldButtonName,
34+
contentWhenDisabled,
3335
}: DateTimePickerFieldParams): JSX.Element => {
3436
const isFieldEnabled = value !== null && value !== undefined;
3537

@@ -60,6 +62,7 @@ export const DateTimePickerField = ({
6062
errorMessage={errorMessage}
6163
isEditable={isEditable}
6264
isFieldEnabled={isFieldEnabled}
65+
contentWhenDisabled={contentWhenDisabled}
6366
variant="form"
6467
addFieldButtonName={addFieldButtonName}
6568
removeFieldButtonName={removeFieldButtonName}

packages/gator-permissions-snap/src/ui/components/Field.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type BaseFieldProps = {
3636
isFieldEnabled?: boolean;
3737
addFieldButtonName?: string | undefined;
3838
removeFieldButtonName?: string | undefined;
39+
contentWhenDisabled?: (() => string) | undefined;
3940
};
4041

4142
export type ViewFieldProps = BaseFieldProps & {
@@ -104,6 +105,7 @@ const isDisplayFieldProps = (props: FieldProps): props is ViewFieldProps => {
104105
* @param props.isFieldEnabled - Whether the field is currently enabled (default: true).
105106
* @param props.addFieldButtonName - Name for the add field button (enables toggle).
106107
* @param props.removeFieldButtonName - Name for the remove field button (enables toggle).
108+
* @param props.contentWhenDisabled - Optional content to show when the field is toggled off.
107109
* @param props.iconData - Optional icon data for display or input fields.
108110
* @param props.removeButtonName - Optional name for the remove button (input fields).
109111
* @param props.children - The content to render inside the field.
@@ -119,6 +121,7 @@ export const Field = (props: FieldProps): JSX.Element => {
119121
isFieldEnabled = true,
120122
addFieldButtonName,
121123
removeFieldButtonName,
124+
contentWhenDisabled,
122125
} = props;
123126

124127
const tooltipElement = tooltip ? <TooltipIcon tooltip={tooltip} /> : null;
@@ -167,7 +170,14 @@ export const Field = (props: FieldProps): JSX.Element => {
167170
* we only show the label section.
168171
*/
169172
if (hasToggleButtons && !isFieldEnabled) {
170-
return <Box direction="vertical">{labelSection}</Box>;
173+
return (
174+
<Box direction="vertical">
175+
{labelSection}
176+
{contentWhenDisabled ? (
177+
<Text color="warning">{contentWhenDisabled()}</Text>
178+
) : null}
179+
</Box>
180+
);
171181
}
172182

173183
if (isInputFieldProps(props) || isDisplayFieldProps(props)) {

packages/gator-permissions-snap/src/ui/components/InputField.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type InputFieldParams = Pick<
1313
| 'isEditable'
1414
| 'iconData'
1515
| 'errorMessage'
16+
| 'contentWhenDisabled'
1617
> & {
1718
name: string;
1819
value: string | undefined;
@@ -30,6 +31,7 @@ export const InputField = ({
3031
isEditable = true,
3132
errorMessage,
3233
iconData,
34+
contentWhenDisabled,
3335
}: InputFieldParams): JSX.Element => {
3436
if (!isEditable) {
3537
return (
@@ -54,6 +56,7 @@ export const InputField = ({
5456
removeFieldButtonName={removeFieldButtonName}
5557
isFieldEnabled={isFieldEnabled}
5658
iconData={iconData}
59+
contentWhenDisabled={contentWhenDisabled}
5760
variant="form"
5861
>
5962
<Input name={name} type={type} value={value} />

packages/gator-permissions-snap/test/core/rules.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ const optionalRule: RuleDefinition<TestContext, TestMetadata> = {
9898
updateContext: (context, value) => ({ ...context, optionalValue: value }),
9999
};
100100

101+
const optionalRuleWithContentWhenDisabled: RuleDefinition<
102+
TestContext,
103+
TestMetadata
104+
> = {
105+
...optionalRule,
106+
name: 'test-optional-rule-with-content',
107+
label: 'Test Optional Rule With Content' as MessageKey,
108+
contentWhenDisabled: () => 'Shown when this field is disabled.',
109+
};
110+
101111
const undefinedValueRule: RuleDefinition<TestContext, TestMetadata> = {
102112
name: 'undefined-value-rule',
103113
label: 'Undefined Value Rule' as MessageKey,
@@ -379,6 +389,28 @@ describe('rules', () => {
379389
`);
380390
});
381391

392+
it('should render contentWhenDisabled when optional rule is toggled off', () => {
393+
const { optionalValue: _omit, ...rest } = mockContext;
394+
const contextWithOptionalDisabled = { ...rest } as TestContext;
395+
396+
const result = renderRule({
397+
rule: optionalRuleWithContentWhenDisabled,
398+
context: contextWithOptionalDisabled,
399+
metadata: mockMetadata,
400+
});
401+
402+
const children = result?.props?.children;
403+
expect(Array.isArray(children)).toBe(true);
404+
expect(children).toHaveLength(2);
405+
const contentWhenDisabledElement = Array.isArray(children)
406+
? (children[1] as { type: string; props: { children: string } })
407+
: undefined;
408+
expect(contentWhenDisabledElement?.type).toBe('Text');
409+
expect(contentWhenDisabledElement?.props?.children).toBe(
410+
'Shown when this field is disabled.',
411+
);
412+
});
413+
382414
it('should render an optional rule with remove button', () => {
383415
const result = renderRule({
384416
rule: optionalRule,

0 commit comments

Comments
 (0)