Skip to content

refactor(editor): Extract users api into rest-api-client package (no-changelog) #18046

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/frontend/@n8n/rest-api-client/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './sso';
export * from './tags';
export * from './templates';
export * from './ui';
export * from './users';
export * from './versions';
export * from './webhooks';
export * from './workflowHistory';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,88 @@
import type {
LoginRequestDto,
PasswordUpdateRequestDto,
Role,
SettingsUpdateRequestDto,
UsersList,
UsersListFilterDto,
UserUpdateRequestDto,
Role,
UsersList,
User,
} from '@n8n/api-types';
import type { Scope } from '@n8n/permissions';
import type {
CurrentUserResponse,
IPersonalizationLatestVersion,
IUserResponse,
} from '@/Interface';
import type { IRestApiContext } from '@n8n/rest-api-client';
import type { IDataObject, IUserSettings } from 'n8n-workflow';
import { makeRestApiRequest } from '@n8n/rest-api-client';
FeatureFlags,
IDataObject,
IPersonalizationSurveyAnswersV4,
IUserSettings,
} from 'n8n-workflow';

import type { IRestApiContext } from '../types';
import { makeRestApiRequest } from '../utils';

export type IPersonalizationSurveyAnswersV1 = {
codingSkill?: string | null;
companyIndustry?: string[] | null;
companySize?: string | null;
otherCompanyIndustry?: string | null;
otherWorkArea?: string | null;
workArea?: string[] | string | null;
};

export type IPersonalizationSurveyAnswersV2 = {
version: 'v2';
automationGoal?: string | null;
codingSkill?: string | null;
companyIndustryExtended?: string[] | null;
companySize?: string | null;
companyType?: string | null;
customerType?: string | null;
mspFocus?: string[] | null;
mspFocusOther?: string | null;
otherAutomationGoal?: string | null;
otherCompanyIndustryExtended?: string[] | null;
};

export type IPersonalizationSurveyAnswersV3 = {
version: 'v3';
automationGoal?: string | null;
otherAutomationGoal?: string | null;
companyIndustryExtended?: string[] | null;
otherCompanyIndustryExtended?: string[] | null;
companySize?: string | null;
companyType?: string | null;
automationGoalSm?: string[] | null;
automationGoalSmOther?: string | null;
usageModes?: string[] | null;
email?: string | null;
};

export type IPersonalizationLatestVersion = IPersonalizationSurveyAnswersV4;

export type IPersonalizationSurveyVersions =
| IPersonalizationSurveyAnswersV1
| IPersonalizationSurveyAnswersV2
| IPersonalizationSurveyAnswersV3
| IPersonalizationSurveyAnswersV4;

export interface IUserResponse extends User {
globalScopes?: Scope[];
personalizationAnswers?: IPersonalizationSurveyVersions | null;
settings?: IUserSettings | null;
}

export interface CurrentUserResponse extends IUserResponse {
featureFlags?: FeatureFlags;
}

export interface IUser extends IUserResponse {
isDefaultUser: boolean;
isPendingUser: boolean;
inviteAcceptUrl?: string;
fullName?: string;
createdAt?: string;
mfaEnabled: boolean;
mfaAuthenticated?: boolean;
}

export async function loginCurrentUser(
context: IRestApiContext,
Expand Down
71 changes: 2 additions & 69 deletions packages/frontend/editor-ui/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
IVersionNotificationSettings,
ROLE,
Role,
User,
} from '@n8n/api-types';
import type { Scope } from '@n8n/permissions';
import type { NodeCreatorTag } from '@n8n/design-system';
Expand Down Expand Up @@ -37,12 +36,10 @@ import type {
ExecutionStatus,
ITelemetryTrackProperties,
WorkflowSettings,
IUserSettings,
INodeExecutionData,
INodeProperties,
NodeConnectionType,
StartNodeData,
IPersonalizationSurveyAnswersV4,
AnnotationVote,
ITaskData,
ISourceData,
Expand Down Expand Up @@ -70,7 +67,8 @@ import type { BulkCommand, Undoable } from '@/models/history';

import type { ProjectSharingData } from '@/types/projects.types';
import type { PathItem } from '@n8n/design-system/components/N8nBreadcrumbs/Breadcrumbs.vue';
import { type IconName } from '@n8n/design-system/src/components/N8nIcon/icons';
import type { IconName } from '@n8n/design-system/src/components/N8nIcon/icons';
import type { IUser, IUserResponse } from '@n8n/rest-api-client/api/users';

export * from '@n8n/design-system/types';

Expand Down Expand Up @@ -531,73 +529,8 @@ export interface IExecutionDeleteFilter {
ids?: string[];
}

export type IPersonalizationSurveyAnswersV1 = {
codingSkill?: string | null;
companyIndustry?: string[] | null;
companySize?: string | null;
otherCompanyIndustry?: string | null;
otherWorkArea?: string | null;
workArea?: string[] | string | null;
};

export type IPersonalizationSurveyAnswersV2 = {
version: 'v2';
automationGoal?: string | null;
codingSkill?: string | null;
companyIndustryExtended?: string[] | null;
companySize?: string | null;
companyType?: string | null;
customerType?: string | null;
mspFocus?: string[] | null;
mspFocusOther?: string | null;
otherAutomationGoal?: string | null;
otherCompanyIndustryExtended?: string[] | null;
};

export type IPersonalizationSurveyAnswersV3 = {
version: 'v3';
automationGoal?: string | null;
otherAutomationGoal?: string | null;
companyIndustryExtended?: string[] | null;
otherCompanyIndustryExtended?: string[] | null;
companySize?: string | null;
companyType?: string | null;
automationGoalSm?: string[] | null;
automationGoalSmOther?: string | null;
usageModes?: string[] | null;
email?: string | null;
};

export type IPersonalizationLatestVersion = IPersonalizationSurveyAnswersV4;

export type IPersonalizationSurveyVersions =
| IPersonalizationSurveyAnswersV1
| IPersonalizationSurveyAnswersV2
| IPersonalizationSurveyAnswersV3
| IPersonalizationSurveyAnswersV4;

export type InvitableRoleName = (typeof ROLE)['Member' | 'Admin'];

export interface IUserResponse extends User {
globalScopes?: Scope[];
personalizationAnswers?: IPersonalizationSurveyVersions | null;
settings?: IUserSettings | null;
}

export interface CurrentUserResponse extends IUserResponse {
featureFlags?: FeatureFlags;
}

export interface IUser extends IUserResponse {
isDefaultUser: boolean;
isPendingUser: boolean;
inviteAcceptUrl?: string;
fullName?: string;
createdAt?: string;
mfaEnabled: boolean;
mfaAuthenticated?: boolean;
}

export interface IUserListAction {
label: string;
value: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/editor-ui/src/__tests__/data/users.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { faker } from '@faker-js/faker';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { SignInType } from '@/constants';

export const createUser = (overrides?: Partial<IUser>): IUser => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Factory } from 'miragejs';
import { faker } from '@faker-js/faker';
import { SignInType } from '@/constants';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

export const userFactory = Factory.extend<IUser>({
id(i: number) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { Model } from 'miragejs';
import type { ModelDefinition } from 'miragejs/-types';

Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/editor-ui/src/api/invitation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CurrentUserResponse, IInviteResponse, InvitableRoleName } from '@/Interface';
import type { IInviteResponse, InvitableRoleName } from '@/Interface';
import type { CurrentUserResponse } from '@n8n/rest-api-client/api/users';
import type { IRestApiContext } from '@n8n/rest-api-client';
import type { IDataObject } from 'n8n-workflow';
import { makeRestApiRequest } from '@n8n/rest-api-client';
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/editor-ui/src/api/workflow-webhooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { post } from '@n8n/rest-api-client';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports a type through a deep sub-path instead of the package’s public entry point, creating an unnecessary tight coupling to internal file structure and risking breakage if the module layout changes.

Prompt for AI agents
Address the following comment on packages/frontend/editor-ui/src/api/workflow-webhooks.ts at line 1:

<comment>Imports a type through a deep sub-path instead of the package’s public entry point, creating an unnecessary tight coupling to internal file structure and risking breakage if the module layout changes.</comment>

<file context>
@@ -1,4 +1,4 @@
-import type { IUser } from &#39;@/Interface&#39;;
+import type { IUser } from &#39;@n8n/rest-api-client/api/users&#39;;
 import { post } from &#39;@n8n/rest-api-client&#39;;
 
</file context>
Suggested change
import type { IUser } from '@n8n/rest-api-client/api/users';
import type { IUser } from '@n8n/rest-api-client';


const N8N_API_BASE_URL = 'https://api.n8n.io/api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { mock } from 'vitest-mock-extended';

import { STORES } from '@n8n/stores';
import CollaborationPane from '@/components/MainHeader/CollaborationPane.vue';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

import type { RenderOptions } from '@/__tests__/render';
import { createComponentRenderer } from '@/__tests__/render';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import type {
FormFieldValueUpdate,
IFormInputs,
IInviteResponse,
IUser,
InvitableRoleName,
} from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { EnterpriseEditionFeature, VALID_EMAIL_REGEX, INVITE_USER_MODAL_KEY } from '@/constants';
import { ROLE } from '@n8n/api-types';
import { useUsersStore } from '@/stores/users.store';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ import {
} from '@/constants';
import { useToast } from '@/composables/useToast';
import Modal from '@/components/Modal.vue';
import type { IFormInputs, IPersonalizationLatestVersion } from '@/Interface';
import type { IFormInputs } from '@/Interface';
import type { IPersonalizationLatestVersion } from '@n8n/rest-api-client/api/users';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule violated: Prefer Typeguards over Type casting

Type assertion with as IPersonalizationLatestVersion is used for type narrowing, which is not allowed by the rule. Use a type guard function or type annotation instead.

Prompt for AI agents
Address the following comment on packages/frontend/editor-ui/src/components/PersonalizationModal.vue at line 87:

<comment>Type assertion with `as IPersonalizationLatestVersion` is used for type narrowing, which is not allowed by the rule. Use a type guard function or type annotation instead.</comment>

<file context>
@@ -83,7 +83,8 @@ import {
 } from &#39;@/constants&#39;;
 import { useToast } from &#39;@/composables/useToast&#39;;
 import Modal from &#39;@/components/Modal.vue&#39;;
-import type { IFormInputs, IPersonalizationLatestVersion } from &#39;@/Interface&#39;;
+import type { IFormInputs } from &#39;@/Interface&#39;;
+import type { IPersonalizationLatestVersion } from &#39;@n8n/rest-api-client/api/users&#39;;
 import { useRootStore } from &#39;@n8n/stores/useRootStore&#39;;
 import { useUsersStore } from &#39;@/stores/users.store&#39;;
</file context>

import { useRootStore } from '@n8n/stores/useRootStore';
import { useUsersStore } from '@/stores/users.store';
import { createFormEventBus } from '@n8n/design-system/utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ROLE, type UsersList } from '@n8n/api-types';
import { type UserAction } from '@n8n/design-system';
import SettingsUsersActionsCell from '@/components/SettingsUsers/SettingsUsersActionsCell.vue';
import { createComponentRenderer } from '@/__tests__/render';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

const baseUser: UsersList['items'][number] = {
id: '1',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup="">
import type { UsersList } from '@n8n/api-types';
import type { UserAction } from '@n8n/design-system';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

const props = defineProps<{
data: UsersList['items'][number];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { type UserAction } from '@n8n/design-system';
import SettingsUsersTable from '@/components/SettingsUsers/SettingsUsersTable.vue';
import { createComponentRenderer } from '@/__tests__/render';
import { useEmitters } from '@/__tests__/utils';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

const { emitters, addEmitter } = useEmitters<
'settingsUsersRoleCell' | 'settingsUsersActionsCell' | 'n8nDataTableServer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
type ActionDropdownItem,
} from '@n8n/design-system';
import type { TableHeader, TableOptions } from '@n8n/design-system/components/N8nDataTableServer';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import SettingsUsersRoleCell from '@/components/SettingsUsers/SettingsUsersRoleCell.vue';
import SettingsUsersProjectsCell from '@/components/SettingsUsers/SettingsUsersProjectsCell.vue';
import SettingsUsersActionsCell from '@/components/SettingsUsers/SettingsUsersActionsCell.vue';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import V1Banner from './V1Banner.vue';
import { createPinia, setActivePinia } from 'pinia';
import { useUsersStore } from '@/stores/users.store';
import { ROLE } from '@n8n/api-types';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

const renderComponent = createComponentRenderer(V1Banner, {
global: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCalloutHelpers } from '@/composables/useCalloutHelpers';
import { updateCurrentUserSettings } from '@/api/users';
import { updateCurrentUserSettings } from '@n8n/rest-api-client/api/users';

const mocks = vi.hoisted(() => ({
resolve: vi.fn(),
Expand Down Expand Up @@ -53,7 +53,7 @@ vi.mock('@n8n/stores/useRootStore', () => ({
}),
}));

vi.mock('@/api/users', () => ({
vi.mock('@n8n/rest-api-client/api/users', () => ({
updateCurrentUserSettings: vi.fn(),
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { usePostHog } from '@/stores/posthog.store';
import { useUsersStore } from '@/stores/users.store';
import { RAG_STARTER_WORKFLOW_EXPERIMENT, VIEWS } from '@/constants';
import { getRagStarterWorkflowJson } from '@/utils/easyAiWorkflowUtils';
import { updateCurrentUserSettings } from '@/api/users';
import { updateCurrentUserSettings } from '@n8n/rest-api-client/api/users';
import { useWorkflowsStore } from '@/stores/workflows.store';

export function useCalloutHelpers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { computed, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { ProjectTypes } from '@/types/projects.types';
import { useProjectsStore } from '@/stores/projects.store';
import type { IUser, SortingAndPaginationUpdates, UserAction } from '@/Interface';
import type { SortingAndPaginationUpdates, UserAction } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import type { DataStoreResource } from '@/features/dataStore/types';
import DataStoreCard from '@/features/dataStore/components/DataStoreCard.vue';
import { useSourceControlStore } from '@/stores/sourceControl.store';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { createComponentRenderer } from '@/__tests__/render';
import DataStoreCard from './DataStoreCard.vue';
import { createPinia, setActivePinia } from 'pinia';
import type { DataStoreResource } from '@/features/dataStore/types';
import type { UserAction, IUser } from '@/Interface';
import type { UserAction } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';

vi.mock('vue-router', () => {
const push = vi.fn();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { IUser, UserAction } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import type { UserAction } from '@/Interface';
import type { DataStoreResource } from '@/features/dataStore/types';
import { DATA_STORE_DETAILS } from '../constants';
import { useI18n } from '@n8n/i18n';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useRootStore } from '@n8n/stores/useRootStore';
import { useUsersStore } from '@/stores/users.store';
import { useSettingsStore } from '@/stores/settings.store';
import { mockedStore, type MockedStore } from '@/__tests__/utils';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { reactive } from 'vue';
import type { FrontendModuleSettings } from '@n8n/api-types';

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/editor-ui/src/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { mockedStore, SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
import { STORES } from '@n8n/stores';
import { useSSOStore } from '@/stores/sso.store';
import { UserManagementAuthenticationMethod } from '@/Interface';
import type { IUser } from '@/Interface';
import type { IUser } from '@n8n/rest-api-client/api/users';
import { EnterpriseEditionFeature } from '@/constants';
import { useUIStore } from '@/stores/ui.store';
import type { Cloud } from '@n8n/rest-api-client';
Expand Down
Loading
Loading