feat(editor): Finalize workers view (#8052)

https://linear.app/n8n/issue/PAY-1065
This commit is contained in:
Iván Ovejero 2023-12-20 17:49:14 +01:00 committed by GitHub
parent d917dfe9f8
commit edfa78414d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 19 additions and 12 deletions

View file

@ -1,4 +1,4 @@
import { INSTANCE_MEMBERS } from '../constants';
import { INSTANCE_MEMBERS, INSTANCE_OWNER } from '../constants';
import { WorkerViewPage } from '../pages';
const workerViewPage = new WorkerViewPage();
@ -29,7 +29,7 @@ describe('Worker View (licensed)', () => {
});
it('should show up in the menu sidebar', () => {
cy.signin(INSTANCE_MEMBERS[0]);
cy.signin(INSTANCE_OWNER);
cy.enableQueueMode();
cy.visit(workerViewPage.url);
workerViewPage.getters.menuItem().should('exist');

View file

@ -16,6 +16,7 @@ export type Resource =
| 'tag'
| 'user'
| 'variable'
| 'workersView'
| 'workflow';
export type ResourceScope<
@ -50,6 +51,7 @@ export type SourceControlScope = ResourceScope<'sourceControl', 'pull' | 'push'
export type TagScope = ResourceScope<'tag'>;
export type UserScope = ResourceScope<'user', DefaultOperations | 'resetPassword' | 'changeRole'>;
export type VariableScope = ResourceScope<'variable'>;
export type WorkersViewScope = ResourceScope<'workersView', 'manage'>;
export type WorkflowScope = ResourceScope<'workflow', DefaultOperations | 'share' | 'execute'>;
export type Scope =
@ -69,6 +71,7 @@ export type Scope =
| TagScope
| UserScope
| VariableScope
| WorkersViewScope
| WorkflowScope;
export type ScopeLevel = 'global' | 'project' | 'resource';

View file

@ -66,6 +66,7 @@ export const ownerPermissions: Scope[] = [
'workflow:list',
'workflow:share',
'workflow:execute',
'workersView:manage',
];
export const adminPermissions: Scope[] = ownerPermissions.concat();
export const memberPermissions: Scope[] = [

View file

@ -31,6 +31,7 @@ import type { BaseTextKey } from '@/plugins/i18n';
import { useUIStore } from '@/stores/ui.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { hasPermission } from '@/rbac/permissions';
export default defineComponent({
name: 'SettingsSidebar',
@ -123,7 +124,8 @@ export default defineComponent({
label: this.$locale.baseText('mainSidebar.workersView'),
position: 'top',
available:
this.settingsStore.isQueueModeEnabled && this.settingsStore.isWorkerViewAvailable,
this.settingsStore.isQueueModeEnabled &&
hasPermission(['rbac'], { rbac: { scope: 'workersView:manage' } }),
activateOnRouteNames: [VIEWS.WORKER_VIEW],
},
];

View file

@ -4,8 +4,8 @@
<div :class="$style.workerListHeader">
<n8n-heading tag="h1" size="2xlarge">{{ pageTitle }}</n8n-heading>
</div>
<div v-if="isMounting">
<n8n-loading :class="$style.tableLoader" variant="custom" />
<div v-if="!initialStatusReceived">
<n8n-spinner />
</div>
<div v-else>
<div v-if="workerIds.length === 0">{{ $locale.baseText('workerList.empty') }}</div>
@ -55,14 +55,8 @@ export default defineComponent({
...pushConnection.setup?.(props, ctx),
};
},
data() {
return {
isMounting: true,
};
},
mounted() {
setPageTitle(`n8n - ${this.pageTitle}`);
this.isMounting = false;
this.$telemetry.track('User viewed worker view', {
instance_id: this.rootStore.instanceId,
@ -91,6 +85,9 @@ export default defineComponent({
}
return returnData;
},
initialStatusReceived(): boolean {
return this.orchestrationManagerStore.initialStatusReceived;
},
workerIds(): string[] {
return Object.keys(this.orchestrationManagerStore.workers);
},

View file

@ -628,7 +628,7 @@
"workerList.actionBox.description": "View the current state of workers connected to your instance.",
"workerList.actionBox.description.link": "More info",
"workerList.actionBox.buttonText": "See plans",
"workerList.docs.url": "https://docs.n8n.io",
"workerList.docs.url": "https://docs.n8n.io/hosting/scaling/queue-mode/#view-running-workers",
"executionSidebar.executionName": "Execution {id}",
"executionSidebar.searchPlaceholder": "Search executions...",
"executionView.onPaste.title": "Cannot paste here",

View file

@ -7,6 +7,7 @@ export const WORKER_HISTORY_LENGTH = 100;
const STALE_SECONDS = 120 * 1000;
export interface IOrchestrationStoreState {
initialStatusReceived: boolean;
workers: { [id: string]: IPushDataWorkerStatusPayload };
workersHistory: {
[id: string]: IWorkerHistoryItem[];
@ -22,6 +23,7 @@ export interface IWorkerHistoryItem {
export const useOrchestrationStore = defineStore('orchestrationManager', {
state: (): IOrchestrationStoreState => ({
initialStatusReceived: false,
workers: {},
workersHistory: {},
workersLastUpdated: {},
@ -38,6 +40,8 @@ export const useOrchestrationStore = defineStore('orchestrationManager', {
this.workersHistory[data.workerId].shift();
}
this.workersLastUpdated[data.workerId] = Date.now();
this.initialStatusReceived = true;
},
removeStaleWorkers() {
for (const id in this.workersLastUpdated) {