mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-31 08:46:58 +02:00
feat(editor): Show data redaction scope dropdown to unlicensed users (#30966)
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.22.3) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.15.0) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
Some checks are pending
CI: Master (Build, Test, Lint) / Build for Github Cache (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (22.22.3) (push) Waiting to run
CI: Master (Build, Test, Lint) / Unit tests (24.15.0) (push) Waiting to run
CI: Master (Build, Test, Lint) / Lint (push) Waiting to run
CI: Master (Build, Test, Lint) / Performance (push) Waiting to run
CI: Master (Build, Test, Lint) / Notify Slack on failure (push) Blocked by required conditions
This commit is contained in:
parent
6d4f917671
commit
25a836dfb7
|
|
@ -202,27 +202,54 @@ function goToUpgrade() {
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="enforced && isLicensed"
|
||||
v-if="!isLicensed || enforced"
|
||||
:class="$style.settingsContainer"
|
||||
data-test-id="redaction-enforcement-scope-row"
|
||||
>
|
||||
<div :class="$style.settingsContainerInfo">
|
||||
<N8nText :bold="true">{{
|
||||
i18n.baseText('settings.security.dataRedaction.scope.title')
|
||||
}}</N8nText>
|
||||
<N8nText :bold="true"
|
||||
>{{ i18n.baseText('settings.security.dataRedaction.scope.title') }}
|
||||
<N8nBadge v-if="!isLicensed" class="ml-4xs">{{
|
||||
i18n.baseText('generic.upgrade')
|
||||
}}</N8nBadge>
|
||||
</N8nText>
|
||||
<N8nText size="small" color="text-light">{{
|
||||
i18n.baseText('settings.security.dataRedaction.scope.description')
|
||||
}}</N8nText>
|
||||
</div>
|
||||
<div :class="$style.settingsContainerAction">
|
||||
<N8nSelect2
|
||||
:model-value="dropdownFloor"
|
||||
:items="floorOptions"
|
||||
size="medium"
|
||||
:disabled="props.managedByEnv || isSaving"
|
||||
data-test-id="redaction-enforcement-scope-select"
|
||||
@update:model-value="onSelectFloor"
|
||||
/>
|
||||
<EnterpriseEdition :features="[EnterpriseEditionFeature.DataRedaction]">
|
||||
<N8nSelect2
|
||||
:model-value="dropdownFloor"
|
||||
:items="floorOptions"
|
||||
size="medium"
|
||||
:disabled="props.managedByEnv || isSaving"
|
||||
data-test-id="redaction-enforcement-scope-select"
|
||||
@update:model-value="onSelectFloor"
|
||||
/>
|
||||
<template #fallback>
|
||||
<N8nTooltip>
|
||||
<N8nSelect2
|
||||
:model-value="dropdownFloor"
|
||||
:items="floorOptions"
|
||||
size="medium"
|
||||
:disabled="true"
|
||||
data-test-id="redaction-enforcement-scope-select"
|
||||
/>
|
||||
<template #content>
|
||||
<I18nT :keypath="TOOLTIP_KEY" tag="span" scope="global">
|
||||
<template #action>
|
||||
<a @click="goToUpgrade">
|
||||
{{
|
||||
i18n.baseText('settings.security.dataRedaction.unlicensed_tooltip.link')
|
||||
}}
|
||||
</a>
|
||||
</template>
|
||||
</I18nT>
|
||||
</template>
|
||||
</N8nTooltip>
|
||||
</template>
|
||||
</EnterpriseEdition>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.settingsCountRow" data-test-id="redaction-enforcement-summary">
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ describe('SecuritySettings', () => {
|
|||
expect(getByTestId('enable-redaction-enforcement')).toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it('should not render scope dropdown when unlicensed even if enforced=true', async () => {
|
||||
it('should render disabled scope dropdown when unlicensed even if enforced=true', async () => {
|
||||
enableRedactionEnforcementFlag(true);
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DataRedaction] = false;
|
||||
getSecuritySettings.mockResolvedValue({
|
||||
|
|
@ -669,13 +669,91 @@ describe('SecuritySettings', () => {
|
|||
redactionEnforcement: { floor: 'production' },
|
||||
});
|
||||
|
||||
const { getByTestId, queryByTestId } = renderView();
|
||||
const { getByTestId } = renderView();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('enable-redaction-enforcement')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(queryByTestId('redaction-enforcement-scope-row')).not.toBeInTheDocument();
|
||||
expect(getByTestId('redaction-enforcement-scope-row')).toBeInTheDocument();
|
||||
expect(getByTestId('redaction-enforcement-scope-select')).toHaveAttribute('data-disabled');
|
||||
});
|
||||
|
||||
it('should render scope dropdown with Upgrade badge when unlicensed and not enforced', async () => {
|
||||
enableRedactionEnforcementFlag(true);
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DataRedaction] = false;
|
||||
|
||||
const { getAllByText, getByTestId } = renderView();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('enable-redaction-enforcement')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(getByTestId('redaction-enforcement-scope-row')).toBeInTheDocument();
|
||||
expect(getByTestId('redaction-enforcement-scope-select')).toHaveAttribute('data-disabled');
|
||||
// One badge on the toggle row, one on the scope row.
|
||||
expect(getAllByText('Upgrade').length).toBeGreaterThanOrEqual(2);
|
||||
// Summary reflects stored floor='off' while the disabled dropdown previews 'production'.
|
||||
expect(getByTestId('redaction-enforcement-summary')).toHaveTextContent('No executions');
|
||||
});
|
||||
|
||||
it('should not call updateSecuritySettings when clicking disabled scope dropdown', async () => {
|
||||
enableRedactionEnforcementFlag(true);
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DataRedaction] = false;
|
||||
getSecuritySettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
redactionEnforcement: { floor: 'production' },
|
||||
});
|
||||
|
||||
const { getByTestId } = renderView();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('redaction-enforcement-scope-select')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await userEvent.click(getByTestId('redaction-enforcement-scope-select'));
|
||||
|
||||
expect(updateSecuritySettings).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show stored scope value when unlicensed with floor=production (downgrade)', async () => {
|
||||
enableRedactionEnforcementFlag(true);
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DataRedaction] = false;
|
||||
getSecuritySettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
redactionEnforcement: { floor: 'production' },
|
||||
});
|
||||
|
||||
const { getByTestId } = renderView();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('redaction-enforcement-scope-row')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(getByTestId('redaction-enforcement-scope-select')).toHaveAttribute('data-disabled');
|
||||
expect(getByTestId('redaction-enforcement-summary')).toHaveTextContent(
|
||||
'Production executions',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show stored scope value when unlicensed with floor=all (downgrade)', async () => {
|
||||
enableRedactionEnforcementFlag(true);
|
||||
settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.DataRedaction] = false;
|
||||
getSecuritySettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
redactionEnforcement: { floor: 'all' },
|
||||
});
|
||||
|
||||
const { getByTestId } = renderView();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('redaction-enforcement-scope-row')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(getByTestId('redaction-enforcement-scope-select')).toHaveAttribute('data-disabled');
|
||||
expect(getByTestId('redaction-enforcement-summary')).toHaveTextContent(
|
||||
'Manual and production executions',
|
||||
);
|
||||
});
|
||||
|
||||
it('should disable toggle when managed by env', async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user