Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(editor): Follow up fixes and improvements to viewer role #10684

Merged
6 changes: 6 additions & 0 deletions packages/editor-ui/src/components/CredentialCard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,10 @@ describe('CredentialCard', () => {
}
expect(actions).toHaveTextContent('Move');
});

it('should set readOnly variant based on prop', () => {
const { getByRole } = renderComponent({ props: { readOnly: true } });
const heading = getByRole('heading');
expect(heading).toHaveTextContent('Read only');
});
});
7 changes: 5 additions & 2 deletions packages/editor-ui/src/components/CredentialCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,19 @@ function moveResource() {
<template #header>
<n8n-heading tag="h2" bold :class="$style.cardHeading">
{{ data.name }}
<N8nBadge v-if="readOnly" class="ml-3xs" theme="tertiary" bold>
{{ locale.baseText('credentials.item.readonly') }}
</N8nBadge>
</n8n-heading>
</template>
<div :class="$style.cardDescription">
<n8n-text color="text-light" size="small">
<span v-if="credentialType">{{ credentialType.displayName }} | </span>
<span v-show="data"
>{{ $locale.baseText('credentials.item.updated') }} <TimeAgo :date="data.updatedAt" /> |
>{{ locale.baseText('credentials.item.updated') }} <TimeAgo :date="data.updatedAt" /> |
</span>
<span v-show="data"
>{{ $locale.baseText('credentials.item.created') }} {{ formattedCreatedAtDate }}
>{{ locale.baseText('credentials.item.created') }} {{ formattedCreatedAtDate }}
</span>
</n8n-text>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ async function beforeClose() {
},
);
keepEditing = confirmAction === MODAL_CONFIRM;
} else if (isOAuthType.value && !isOAuthConnected.value) {
} else if (credentialPermissions.value.update && isOAuthType.value && !isOAuthConnected.value) {
const confirmAction = await message.confirm(
i18n.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.message'),
i18n.baseText('credentialEdit.credentialEdit.confirmMessage.beforeClose2.headline'),
Expand Down
10 changes: 9 additions & 1 deletion packages/editor-ui/src/components/WorkflowCard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('WorkflowCard', () => {
it('should render a card with the workflow name and open workflow clicking on it', async () => {
const data = createWorkflow();
const { getByRole } = renderComponent({ props: { data } });
const cardTitle = getByRole('heading', { level: 2, name: data.name });
const cardTitle = getByRole('heading', { level: 2, name: new RegExp(data.name) });

expect(cardTitle).toBeInTheDocument();

Expand Down Expand Up @@ -166,4 +166,12 @@ describe('WorkflowCard', () => {
}
expect(actions).toHaveTextContent('Move');
});

it('should show Read only mode', async () => {
const data = createWorkflow();
const { getByRole } = renderComponent({ props: { data } });

const heading = getByRole('heading');
expect(heading).toHaveTextContent('Read only');
});
});
7 changes: 5 additions & 2 deletions packages/editor-ui/src/components/WorkflowCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,19 @@ function moveResource() {
<template #header>
<n8n-heading tag="h2" bold :class="$style.cardHeading" data-test-id="workflow-card-name">
{{ data.name }}
<N8nBadge v-if="!workflowPermissions.update" class="ml-3xs" theme="tertiary" bold>
{{ locale.baseText('workflows.item.readonly') }}
</N8nBadge>
</n8n-heading>
</template>
<div :class="$style.cardDescription">
<n8n-text color="text-light" size="small">
<span v-show="data"
>{{ $locale.baseText('workflows.item.updated') }}
>{{ locale.baseText('workflows.item.updated') }}
<TimeAgo :date="String(data.updatedAt)" /> |
</span>
<span v-show="data" class="mr-2xs"
>{{ $locale.baseText('workflows.item.created') }} {{ formattedCreatedAtDate }}
>{{ locale.baseText('workflows.item.created') }} {{ formattedCreatedAtDate }}
</span>
<span
v-if="settingsStore.areTagsEnabled && data.tags && data.tags.length > 0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,34 @@ describe('WorkflowExecutionsPreview.vue', () => {
expect(router.currentRoute.value.path).toBe(path);
},
);

it('disables teh stop execution button when the user cannot update', () => {
cstuncsik marked this conversation as resolved.
Show resolved Hide resolved
settingsStore.settings.enterprise = {
...(settingsStore.settings.enterprise ?? {}),
};
vi.spyOn(workflowsStore, 'getWorkflowById').mockReturnValue({
scopes: undefined,
} as IWorkflowDb);
const { getByTestId } = render(WorkflowExecutionsPreview, {
cstuncsik marked this conversation as resolved.
Show resolved Hide resolved
props: {
execution: { ...executionData, status: 'running' },
},
global: {
plugins: [
I18nPlugin,
i18nInstance,
PiniaVuePlugin,
FontAwesomePlugin,
GlobalComponentsPlugin,
pinia,
router,
],
mocks: {
$route,
},
},
});

expect(getByTestId('stop-execution')).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ function onRetryButtonBlur(event: FocusEvent) {
<N8nText :class="$style.runningMessage" color="text-light">
{{ locale.baseText('executionDetails.runningMessage') }}
</N8nText>
<N8nButton class="mt-l" type="tertiary" @click="handleStopClick">
<N8nButton
data-test-id="stop-execution"
class="mt-l"
type="tertiary"
:disabled="!workflowPermissions.execute"
@click="handleStopClick"
>
{{ locale.baseText('executionsList.stopExecution') }}
</N8nButton>
</div>
Expand Down
2 changes: 2 additions & 0 deletions packages/editor-ui/src/plugins/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@
"credentials.item.updated": "Last updated",
"credentials.item.created": "Created",
"credentials.item.owner": "Owner",
"credentials.item.readonly": "Read only",
"credentials.search.placeholder": "Search credentials...",
"credentials.filters.type": "Type",
"credentials.filters.active": "Some credentials may be hidden since filters are applied.",
Expand Down Expand Up @@ -2205,6 +2206,7 @@
"workflows.item.move": "Move",
"workflows.item.updated": "Last updated",
"workflows.item.created": "Created",
"workflows.item.readonly": "Read only",
"workflows.search.placeholder": "Search workflows...",
"workflows.filters": "Filters",
"workflows.filters.tags": "Tags",
Expand Down
35 changes: 35 additions & 0 deletions packages/editor-ui/src/views/CredentialsView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,40 @@ describe('CredentialsView', () => {
null,
);
});

it('should disable cards based on permissions', () => {
vi.spyOn(credentialsStore, 'allCredentials', 'get').mockReturnValue([
{
id: '1',
name: 'test',
type: 'test',
createdAt: '2021-05-05T00:00:00Z',
updatedAt: '2021-05-05T00:00:00Z',
scopes: ['credential:update'],
},
{
id: '2',
name: 'test2',
type: 'test2',
createdAt: '2021-05-05T00:00:00Z',
updatedAt: '2021-05-05T00:00:00Z',
},
]);

renderComponent();
expect(ResourcesListLayout.setup).toHaveBeenCalledWith(
expect.objectContaining({
resources: [
expect.objectContaining({
readOnly: false,
}),
expect.objectContaining({
readOnly: true,
}),
],
}),
null,
);
});
});
});
8 changes: 7 additions & 1 deletion packages/editor-ui/src/views/CredentialsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export default defineComponent({
scopes: credential.scopes,
type: credential.type,
sharedWithProjects: credential.sharedWithProjects,
readOnly: !getResourcePermissions(credential.scopes).credential.update,
}));
},
allCredentialTypes(): ICredentialType[] {
Expand Down Expand Up @@ -179,7 +180,12 @@ export default defineComponent({
</div>
</template>
<template #default="{ data }">
<CredentialCard data-test-id="resources-list-item" class="mb-2xs" :data="data" />
<CredentialCard
data-test-id="resources-list-item"
class="mb-2xs"
:data="data"
:read-only="data.readOnly"
/>
</template>
<template #filters="{ setKeyValue }">
<div class="mb-s">
Expand Down
Loading