mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
refactor(editor): Remove the restApi
mixin (#6065)
* ✨ Removing the `makeApiRequest` method from `restAPI` mixin, removing the mixing from the App component * ✨ Removing `restApi` mixin * 👕 Fixing lint errors * ✔️ Fixing execution list unit tests and merge bug in workflowRun mixin * 🐛 Added missing useStore
This commit is contained in:
parent
4bd55f7a1e
commit
59db96771e
|
@ -37,7 +37,6 @@ import { showMessage } from '@/mixins/showMessage';
|
|||
import { userHelpers } from '@/mixins/userHelpers';
|
||||
import { loadLanguage } from './plugins/i18n';
|
||||
import useGlobalLinkActions from '@/composables/useGlobalLinkActions';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from './stores/ui';
|
||||
import { useSettingsStore } from './stores/settings';
|
||||
|
@ -49,7 +48,7 @@ import { useHistoryHelper } from '@/composables/useHistoryHelper';
|
|||
import { newVersions } from '@/mixins/newVersions';
|
||||
import { useRoute } from 'vue-router/composables';
|
||||
|
||||
export default mixins(newVersions, showMessage, userHelpers, restApi).extend({
|
||||
export default mixins(newVersions, showMessage, userHelpers).extend({
|
||||
name: 'App',
|
||||
components: {
|
||||
LoadingView,
|
||||
|
|
|
@ -139,43 +139,6 @@ export interface IExternalHooks {
|
|||
run(eventName: string, metadata?: IDataObject): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not add methods to this interface.
|
||||
*/
|
||||
export interface IRestApi {
|
||||
getActiveWorkflows(): Promise<string[]>;
|
||||
getActivationError(id: string): Promise<IActivationError | undefined>;
|
||||
getCurrentExecutions(filter: ExecutionsQueryFilter): Promise<IExecutionsCurrentSummaryExtended[]>;
|
||||
getPastExecutions(
|
||||
filter: ExecutionsQueryFilter,
|
||||
limit: number,
|
||||
lastId?: string,
|
||||
firstId?: string,
|
||||
): Promise<IExecutionsListResponse>;
|
||||
stopCurrentExecution(executionId: string): Promise<IExecutionsStopData>;
|
||||
makeRestApiRequest(method: string, endpoint: string, data?: any): Promise<any>;
|
||||
getCredentialTranslation(credentialType: string): Promise<object>;
|
||||
removeTestWebhook(workflowId: string): Promise<boolean>;
|
||||
runWorkflow(runData: IStartRunData): Promise<IExecutionPushResponse>;
|
||||
createNewWorkflow(sendData: IWorkflowDataUpdate): Promise<IWorkflowDb>;
|
||||
updateWorkflow(id: string, data: IWorkflowDataUpdate, forceSave?: boolean): Promise<IWorkflowDb>;
|
||||
deleteWorkflow(name: string): Promise<void>;
|
||||
getWorkflow(id: string): Promise<IWorkflowDb>;
|
||||
getWorkflows(filter?: object): Promise<IWorkflowShortResponse[]>;
|
||||
getWorkflowFromUrl(url: string): Promise<IWorkflowDb>;
|
||||
getExecution(id: string): Promise<IExecutionResponse | undefined>;
|
||||
deleteExecutions(sendData: IExecutionDeleteFilter): Promise<void>;
|
||||
retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean>;
|
||||
getTimezones(): Promise<IDataObject>;
|
||||
getBinaryUrl(
|
||||
dataPath: string,
|
||||
mode: 'view' | 'download',
|
||||
fileName?: string,
|
||||
mimeType?: string,
|
||||
): string;
|
||||
getExecutionEvents(id: string): Promise<IAbstractEventMessage[]>;
|
||||
}
|
||||
|
||||
export interface INodeTranslationHeaders {
|
||||
data: {
|
||||
[key: string]: {
|
||||
|
|
|
@ -26,11 +26,10 @@ import BinaryDataDisplayEmbed from '@/components/BinaryDataDisplayEmbed.vue';
|
|||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
|
||||
export default mixins(nodeHelpers, restApi).extend({
|
||||
export default mixins(nodeHelpers).extend({
|
||||
name: 'BinaryDataDisplay',
|
||||
components: {
|
||||
BinaryDataDisplayEmbed,
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { IBinaryData, jsonParse } from 'n8n-workflow';
|
||||
import type { PropType } from 'vue';
|
||||
import VueJsonPretty from 'vue-json-pretty';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useWorkflowsStore } from '@/stores';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default mixins(restApi).extend({
|
||||
export default Vue.extend({
|
||||
name: 'BinaryDataDisplayEmbed',
|
||||
components: {
|
||||
VueJsonPretty,
|
||||
|
@ -44,6 +45,9 @@ export default mixins(restApi).extend({
|
|||
jsonData: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useWorkflowsStore),
|
||||
},
|
||||
async mounted() {
|
||||
const { id, data, fileName, fileType, mimeType } = (this.binaryData || {}) as IBinaryData;
|
||||
const isJSONData = fileType === 'json';
|
||||
|
@ -56,7 +60,7 @@ export default mixins(restApi).extend({
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
const binaryUrl = this.restApi().getBinaryUrl(id, 'view', fileName, mimeType);
|
||||
const binaryUrl = this.workflowsStore.getBinaryUrl(id, 'view', fileName, mimeType);
|
||||
if (isJSONData) {
|
||||
this.jsonData = await (await fetch(binaryUrl)).json();
|
||||
} else {
|
||||
|
|
|
@ -135,9 +135,7 @@ import Banner from '../Banner.vue';
|
|||
import CopyInput from '../CopyInput.vue';
|
||||
import CredentialInputs from './CredentialInputs.vue';
|
||||
import OauthButton from './OauthButton.vue';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { addCredentialTranslation } from '@/plugins/i18n';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { BUILTIN_CREDENTIALS_DOCS_URL, DOCS_DOMAIN, EnterpriseEditionFeature } from '@/constants';
|
||||
import { IPermissions } from '@/permissions';
|
||||
import { mapStores } from 'pinia';
|
||||
|
@ -147,12 +145,12 @@ import { useRootStore } from '@/stores/n8nRootStore';
|
|||
import { useNDVStore } from '@/stores/ndv';
|
||||
import { useCredentialsStore } from '@/stores/credentials';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
import { ICredentialsResponse, IUpdateInformation, NodeAuthenticationOption } from '@/Interface';
|
||||
import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
||||
import { ICredentialsResponse } from '@/Interface';
|
||||
import AuthTypeSelector from '@/components/CredentialEdit/AuthTypeSelector.vue';
|
||||
import GoogleAuthButton from './GoogleAuthButton.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default mixins(restApi).extend({
|
||||
export default Vue.extend({
|
||||
name: 'CredentialConfig',
|
||||
components: {
|
||||
AuthTypeSelector,
|
||||
|
@ -160,7 +158,6 @@ export default mixins(restApi).extend({
|
|||
CopyInput,
|
||||
CredentialInputs,
|
||||
OauthButton,
|
||||
ParameterInputFull,
|
||||
GoogleAuthButton,
|
||||
},
|
||||
props: {
|
||||
|
@ -226,7 +223,9 @@ export default mixins(restApi).extend({
|
|||
|
||||
if (this.$locale.exists(key)) return;
|
||||
|
||||
const credTranslation = await this.restApi().getCredentialTranslation(this.credentialType.name);
|
||||
const credTranslation = await this.credentialsStore.getCredentialTranslation(
|
||||
this.credentialType.name,
|
||||
);
|
||||
|
||||
addCredentialTranslation(
|
||||
{ [this.credentialType.name]: credTranslation },
|
||||
|
|
|
@ -56,7 +56,6 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
|
|||
import { showMessage } from '@/mixins/showMessage';
|
||||
import TagsDropdown from '@/components/TagsDropdown.vue';
|
||||
import Modal from './Modal.vue';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
|
@ -64,8 +63,9 @@ import { IWorkflowDataUpdate } from '@/Interface';
|
|||
import { getWorkflowPermissions, IPermissions } from '@/permissions';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
import { createEventBus } from '@/event-bus';
|
||||
import { useCredentialsStore } from '@/stores';
|
||||
|
||||
export default mixins(showMessage, workflowHelpers, restApi).extend({
|
||||
export default mixins(showMessage, workflowHelpers).extend({
|
||||
components: { TagsDropdown, Modal },
|
||||
name: 'DuplicateWorkflow',
|
||||
props: ['modalName', 'isActive', 'data'],
|
||||
|
@ -87,7 +87,7 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
|
|||
this.$nextTick(() => this.focusOnNameInput());
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useUsersStore, useSettingsStore, useWorkflowsStore),
|
||||
...mapStores(useCredentialsStore, useUsersStore, useSettingsStore, useWorkflowsStore),
|
||||
workflowPermissions(): IPermissions {
|
||||
const isEmptyWorkflow = this.data.id === PLACEHOLDER_EMPTY_WORKFLOW_ID;
|
||||
const isCurrentWorkflowEmpty =
|
||||
|
@ -150,7 +150,7 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
|
|||
let workflowToUpdate: IWorkflowDataUpdate | undefined;
|
||||
if (currentWorkflowId !== PLACEHOLDER_EMPTY_WORKFLOW_ID) {
|
||||
const { createdAt, updatedAt, usedCredentials, ...workflow } =
|
||||
await this.restApi().getWorkflow(this.data.id);
|
||||
await this.workflowsStore.fetchWorkflow(this.data.id);
|
||||
workflowToUpdate = workflow;
|
||||
|
||||
this.removeForeignCredentialsFromWorkflow(
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -86,10 +86,9 @@ import mixins from 'vue-typed-mixins';
|
|||
import { executionHelpers, IExecutionUIData } from '@/mixins/executionsHelpers';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import ExecutionTime from '@/components/ExecutionTime.vue';
|
||||
|
||||
export default mixins(executionHelpers, showMessage, restApi).extend({
|
||||
export default mixins(executionHelpers, showMessage).extend({
|
||||
name: 'execution-card',
|
||||
components: {
|
||||
ExecutionTime,
|
||||
|
|
|
@ -127,7 +127,6 @@
|
|||
|
||||
<script lang="ts">
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import WorkflowPreview from '@/components/WorkflowPreview.vue';
|
||||
import { executionHelpers, IExecutionUIData } from '@/mixins/executionsHelpers';
|
||||
|
@ -135,11 +134,10 @@ import { VIEWS } from '@/constants';
|
|||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { Dropdown as ElDropdown } from 'element-ui';
|
||||
import { IAbstractEventMessage } from 'n8n-workflow';
|
||||
|
||||
type RetryDropdownRef = InstanceType<typeof ElDropdown> & { hide: () => void };
|
||||
|
||||
export default mixins(restApi, showMessage, executionHelpers).extend({
|
||||
export default mixins(showMessage, executionHelpers).extend({
|
||||
name: 'execution-preview',
|
||||
components: {
|
||||
ElDropdown,
|
||||
|
|
|
@ -49,7 +49,6 @@ import {
|
|||
NodeHelpers,
|
||||
} from 'n8n-workflow';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Route } from 'vue-router';
|
||||
|
@ -71,13 +70,7 @@ const MAX_LOADING_ATTEMPTS = 5;
|
|||
// Number of executions fetched on each page
|
||||
const LOAD_MORE_PAGE_SIZE = 100;
|
||||
|
||||
export default mixins(
|
||||
restApi,
|
||||
showMessage,
|
||||
executionHelpers,
|
||||
debounceHelper,
|
||||
workflowHelpers,
|
||||
).extend({
|
||||
export default mixins(showMessage, executionHelpers, debounceHelper, workflowHelpers).extend({
|
||||
name: 'executions-list',
|
||||
components: {
|
||||
ExecutionsSidebar,
|
||||
|
@ -225,7 +218,7 @@ export default mixins(
|
|||
|
||||
let data: IExecutionsListResponse;
|
||||
try {
|
||||
data = await this.restApi().getPastExecutions(this.requestFilter, limit, lastId);
|
||||
data = await this.workflowsStore.getPastExecutions(this.requestFilter, limit, lastId);
|
||||
} catch (error) {
|
||||
this.loadingMore = false;
|
||||
this.$showError(error, this.$locale.baseText('executionsList.showError.loadMore.title'));
|
||||
|
@ -260,7 +253,7 @@ export default mixins(
|
|||
this.executions[executionIndex - 1] ||
|
||||
this.executions[0];
|
||||
|
||||
await this.restApi().deleteExecutions({ ids: [this.$route.params.executionId] });
|
||||
await this.workflowsStore.deleteExecutions({ ids: [this.$route.params.executionId] });
|
||||
if (this.temporaryExecution?.id === this.$route.params.executionId) {
|
||||
this.temporaryExecution = null;
|
||||
}
|
||||
|
@ -300,7 +293,7 @@ export default mixins(
|
|||
const activeExecutionId = this.$route.params.executionId;
|
||||
|
||||
try {
|
||||
await this.restApi().stopCurrentExecution(activeExecutionId);
|
||||
await this.workflowsStore.stopCurrentExecution(activeExecutionId);
|
||||
|
||||
this.$showMessage({
|
||||
title: this.$locale.baseText('executionsList.showMessage.stopExecution.title'),
|
||||
|
@ -498,7 +491,7 @@ export default mixins(
|
|||
|
||||
let data: IWorkflowDb | undefined;
|
||||
try {
|
||||
data = await this.restApi().getWorkflow(workflowId);
|
||||
data = await this.workflowsStore.fetchWorkflow(workflowId);
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('nodeView.showError.openWorkflow.title'));
|
||||
return;
|
||||
|
@ -644,7 +637,7 @@ export default mixins(
|
|||
}
|
||||
},
|
||||
async loadActiveWorkflows(): Promise<void> {
|
||||
this.workflowsStore.activeWorkflows = await this.restApi().getActiveWorkflows();
|
||||
await this.workflowsStore.fetchActiveWorkflows();
|
||||
},
|
||||
async onRetryExecution(payload: { execution: IExecutionsSummary; command: string }) {
|
||||
const loadWorkflow = payload.command === 'current-workflow';
|
||||
|
@ -665,7 +658,10 @@ export default mixins(
|
|||
},
|
||||
async retryExecution(execution: IExecutionsSummary, loadWorkflow?: boolean) {
|
||||
try {
|
||||
const retrySuccessful = await this.restApi().retryExecution(execution.id, loadWorkflow);
|
||||
const retrySuccessful = await this.workflowsStore.retryExecution(
|
||||
execution.id,
|
||||
loadWorkflow,
|
||||
);
|
||||
|
||||
if (retrySuccessful === true) {
|
||||
this.$showMessage({
|
||||
|
|
|
@ -509,7 +509,7 @@ export default mixins(workflowHelpers).extend({
|
|||
}
|
||||
|
||||
try {
|
||||
await this.restApi().deleteWorkflow(this.currentWorkflowId);
|
||||
await this.workflowsStore.deleteWorkflowAPI(this.currentWorkflowId);
|
||||
} catch (error) {
|
||||
this.$showError(
|
||||
error,
|
||||
|
|
|
@ -97,7 +97,6 @@ import GiftNotificationIcon from './GiftNotificationIcon.vue';
|
|||
import WorkflowSettings from '@/components/WorkflowSettings.vue';
|
||||
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
import { workflowRun } from '@/mixins/workflowRun';
|
||||
|
@ -118,7 +117,6 @@ import { isNavigationFailure } from 'vue-router';
|
|||
|
||||
export default mixins(
|
||||
genericHelpers,
|
||||
restApi,
|
||||
showMessage,
|
||||
workflowHelpers,
|
||||
workflowRun,
|
||||
|
|
|
@ -98,7 +98,6 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import {
|
||||
ICredentialsResponse,
|
||||
INodeUi,
|
||||
|
@ -142,7 +141,7 @@ interface CredentialDropdownOption extends ICredentialsResponse {
|
|||
typeDisplayName: string;
|
||||
}
|
||||
|
||||
export default mixins(genericHelpers, nodeHelpers, restApi, showMessage).extend({
|
||||
export default mixins(genericHelpers, nodeHelpers, showMessage).extend({
|
||||
name: 'NodeCredentials',
|
||||
props: {
|
||||
readonly: {
|
||||
|
|
|
@ -171,7 +171,7 @@ export default mixins(workflowRun, pinData).extend({
|
|||
methods: {
|
||||
async stopWaitingForWebhook() {
|
||||
try {
|
||||
await this.restApi().removeTestWebhook(this.workflowsStore.workflowId);
|
||||
await this.workflowsStore.removeTestWebhook(this.workflowsStore.workflowId);
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('ndv.execute.stopWaitingForWebhook.error'));
|
||||
return;
|
||||
|
|
|
@ -1251,7 +1251,7 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
|
|||
const { id, data, fileName, fileExtension, mimeType } = this.binaryData[index][key];
|
||||
|
||||
if (id) {
|
||||
const url = this.restApi().getBinaryUrl(id, 'download', fileName, mimeType);
|
||||
const url = this.workflowsStore.getBinaryUrl(id, 'download', fileName, mimeType);
|
||||
saveAs(url, [fileName, fileExtension].join('.'));
|
||||
return;
|
||||
} else {
|
||||
|
|
|
@ -86,7 +86,7 @@ const workflowName = ref('');
|
|||
onMounted(async () => {
|
||||
const currentSettings = getCurrentSettings();
|
||||
try {
|
||||
const { name } = await workflowStore.fetchWorkflow(
|
||||
const { name } = await workflowStore.fetchAndSetWorkflow(
|
||||
currentSettings?.firstSuccessfulWorkflowId ?? '',
|
||||
);
|
||||
workflowName.value = name;
|
||||
|
|
|
@ -105,7 +105,7 @@ export default mixins(showMessage, workflowActivate).extend({
|
|||
async displayActivationError() {
|
||||
let errorMessage: string;
|
||||
try {
|
||||
const errorData = await this.restApi().getActivationError(this.workflowId);
|
||||
const errorData = await this.workflowsStore.getActivationError(this.workflowId);
|
||||
|
||||
if (errorData === undefined) {
|
||||
errorMessage = this.$locale.baseText(
|
||||
|
|
|
@ -73,7 +73,6 @@ import {
|
|||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { getWorkflowPermissions, IPermissions } from '@/permissions';
|
||||
import dateformat from 'dateformat';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import WorkflowActivator from '@/components/WorkflowActivator.vue';
|
||||
import Vue from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
@ -91,7 +90,7 @@ export const WORKFLOW_LIST_ITEM_ACTIONS = {
|
|||
DELETE: 'delete',
|
||||
};
|
||||
|
||||
export default mixins(showMessage, restApi).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
data() {
|
||||
return {
|
||||
EnterpriseEditionFeature,
|
||||
|
@ -234,7 +233,7 @@ export default mixins(showMessage, restApi).extend({
|
|||
}
|
||||
|
||||
try {
|
||||
await this.restApi().deleteWorkflow(this.data.id);
|
||||
await this.workflowsStore.deleteWorkflowAPI(this.data.id);
|
||||
this.workflowsStore.deleteWorkflow(this.data.id);
|
||||
} catch (error) {
|
||||
this.$showError(
|
||||
|
|
|
@ -327,7 +327,6 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import {
|
||||
|
@ -357,7 +356,7 @@ import useWorkflowsEEStore from '@/stores/workflows.ee';
|
|||
import { useUsersStore } from '@/stores/users';
|
||||
import { createEventBus } from '@/event-bus';
|
||||
|
||||
export default mixins(externalHooks, genericHelpers, restApi, showMessage).extend({
|
||||
export default mixins(externalHooks, genericHelpers, showMessage).extend({
|
||||
name: 'WorkflowSettings',
|
||||
components: {
|
||||
Modal,
|
||||
|
@ -703,7 +702,7 @@ export default mixins(externalHooks, genericHelpers, restApi, showMessage).exten
|
|||
return;
|
||||
}
|
||||
|
||||
const timezones = await this.restApi().getTimezones();
|
||||
const timezones = await this.settingsStore.getTimezones();
|
||||
|
||||
let defaultTimezoneValue = timezones[this.defaultValues.timezone] as string | undefined;
|
||||
if (defaultTimezoneValue === undefined) {
|
||||
|
@ -724,7 +723,7 @@ export default mixins(externalHooks, genericHelpers, restApi, showMessage).exten
|
|||
}
|
||||
},
|
||||
async loadWorkflows() {
|
||||
const workflows = await this.restApi().getWorkflows();
|
||||
const workflows = await this.workflowsStore.fetchAllWorkflows();
|
||||
workflows.sort((a, b) => {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
||||
return -1;
|
||||
|
@ -789,7 +788,7 @@ export default mixins(externalHooks, genericHelpers, restApi, showMessage).exten
|
|||
data.versionId = this.workflowsStore.workflowVersionId;
|
||||
|
||||
try {
|
||||
const workflow = await this.restApi().updateWorkflow(this.$route.params.name, data);
|
||||
const workflow = await this.workflowsStore.updateWorkflow(this.$route.params.name, data);
|
||||
this.workflowsStore.setWorkflowVersionId(workflow.versionId);
|
||||
} catch (error) {
|
||||
this.$showError(
|
||||
|
|
|
@ -448,7 +448,7 @@ export default mixins(showMessage).extend({
|
|||
this.workflow.id !== PLACEHOLDER_EMPTY_WORKFLOW_ID &&
|
||||
!this.workflow.sharedWith?.length // Sharing info already loaded
|
||||
) {
|
||||
await this.workflowsStore.fetchWorkflow(this.workflow.id);
|
||||
await this.workflowsStore.fetchAndSetWorkflow(this.workflow.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,21 @@ import { genericHelpers } from '@/mixins/genericHelpers';
|
|||
import { executionHelpers } from '@/mixins/executionsHelpers';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { i18nInstance } from '@/plugins/i18n';
|
||||
import type { IWorkflowShortResponse } from '@/Interface';
|
||||
import type { IWorkflowDb } from '@/Interface';
|
||||
import type { IExecutionsSummary } from 'n8n-workflow';
|
||||
import { waitAllPromises } from '@/__tests__/utils';
|
||||
import { useWorkflowsStore } from '@/stores';
|
||||
|
||||
const workflowDataFactory = (): IWorkflowShortResponse => ({
|
||||
const workflowDataFactory = (): IWorkflowDb => ({
|
||||
createdAt: faker.date.past().toDateString(),
|
||||
updatedAt: faker.date.past().toDateString(),
|
||||
id: faker.datatype.uuid(),
|
||||
name: faker.datatype.string(),
|
||||
active: faker.datatype.boolean(),
|
||||
tags: [],
|
||||
nodes: [],
|
||||
connections: {},
|
||||
versionId: faker.datatype.number().toString(),
|
||||
});
|
||||
|
||||
const executionDataFactory = (): IExecutionsSummary => ({
|
||||
|
@ -45,20 +49,6 @@ const executionsData = Array.from({ length: 2 }, () => ({
|
|||
estimated: false,
|
||||
}));
|
||||
|
||||
let getPastExecutionsSpy = vi.fn().mockResolvedValue({ count: 0, results: [], estimated: false });
|
||||
|
||||
const mockRestApiMixin = defineComponent({
|
||||
methods: {
|
||||
restApi() {
|
||||
return {
|
||||
getWorkflows: vi.fn().mockResolvedValue(workflowsData),
|
||||
getCurrentExecutions: vi.fn().mockResolvedValue([]),
|
||||
getPastExecutions: getPastExecutionsSpy,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const renderOptions = {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
|
@ -83,7 +73,7 @@ const renderOptions = {
|
|||
}),
|
||||
i18n: i18nInstance,
|
||||
stubs: ['font-awesome-icon'],
|
||||
mixins: [externalHooks, genericHelpers, executionHelpers, showMessage, mockRestApiMixin],
|
||||
mixins: [externalHooks, genericHelpers, executionHelpers, showMessage],
|
||||
};
|
||||
|
||||
function TelemetryPlugin(vue: typeof Vue): void {
|
||||
|
@ -113,7 +103,22 @@ Vue.use(TelemetryPlugin);
|
|||
Vue.use(PiniaVuePlugin);
|
||||
|
||||
describe('ExecutionsList.vue', () => {
|
||||
const workflowsStore: ReturnType<typeof useWorkflowsStore> = useWorkflowsStore();
|
||||
beforeEach(() => {
|
||||
vi.spyOn(workflowsStore, 'fetchAllWorkflows').mockResolvedValue(workflowsData);
|
||||
vi.spyOn(workflowsStore, 'getCurrentExecutions').mockResolvedValue([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render empty list', async () => {
|
||||
vi.spyOn(workflowsStore, 'getPastExecutions').mockResolvedValueOnce({
|
||||
count: 0,
|
||||
results: [],
|
||||
estimated: false,
|
||||
});
|
||||
const { queryAllByTestId, queryByTestId, getByTestId } = await renderComponent();
|
||||
await userEvent.click(getByTestId('execution-auto-refresh-checkbox'));
|
||||
|
||||
|
@ -124,8 +129,8 @@ describe('ExecutionsList.vue', () => {
|
|||
});
|
||||
|
||||
it('should handle selection flow when loading more items', async () => {
|
||||
getPastExecutionsSpy = vi
|
||||
.fn()
|
||||
const storeSpy = vi
|
||||
.spyOn(workflowsStore, 'getPastExecutions')
|
||||
.mockResolvedValueOnce(executionsData[0])
|
||||
.mockResolvedValueOnce(executionsData[1]);
|
||||
|
||||
|
@ -134,7 +139,7 @@ describe('ExecutionsList.vue', () => {
|
|||
|
||||
await userEvent.click(getByTestId('select-visible-executions-checkbox'));
|
||||
|
||||
expect(getPastExecutionsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(storeSpy).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
|
@ -145,7 +150,7 @@ describe('ExecutionsList.vue', () => {
|
|||
|
||||
await userEvent.click(getByTestId('load-more-button'));
|
||||
|
||||
expect(getPastExecutionsSpy).toHaveBeenCalledTimes(2);
|
||||
expect(storeSpy).toHaveBeenCalledTimes(2);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
|
|
|
@ -32,11 +32,8 @@ import {
|
|||
IUser,
|
||||
} from '@/Interface';
|
||||
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
|
||||
import { get } from 'lodash-es';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { isObjectLiteral } from '@/utils';
|
||||
import { getCredentialPermissions } from '@/permissions';
|
||||
import { mapStores } from 'pinia';
|
||||
|
@ -45,8 +42,9 @@ import { useUsersStore } from '@/stores/users';
|
|||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
import { useCredentialsStore } from '@/stores/credentials';
|
||||
import Vue from 'vue';
|
||||
|
||||
export const nodeHelpers = mixins(restApi).extend({
|
||||
export const nodeHelpers = Vue.extend({
|
||||
computed: {
|
||||
...mapStores(
|
||||
useCredentialsStore,
|
||||
|
|
|
@ -44,7 +44,6 @@ import {
|
|||
} from '../Interface';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
|
||||
|
@ -325,7 +324,7 @@ function executeData(
|
|||
return executeData;
|
||||
}
|
||||
|
||||
export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showMessage).extend({
|
||||
export const workflowHelpers = mixins(externalHooks, nodeHelpers, showMessage).extend({
|
||||
computed: {
|
||||
...mapStores(
|
||||
useNodeTypesStore,
|
||||
|
@ -664,7 +663,7 @@ export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showM
|
|||
if (isCurrentWorkflow) {
|
||||
data = await this.getWorkflowDataToSave();
|
||||
} else {
|
||||
const { versionId } = await this.restApi().getWorkflow(workflowId);
|
||||
const { versionId } = await this.workflowsStore.fetchWorkflow(workflowId);
|
||||
data.versionId = versionId;
|
||||
}
|
||||
|
||||
|
@ -672,7 +671,7 @@ export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showM
|
|||
data.active = active;
|
||||
}
|
||||
|
||||
const workflow = await this.restApi().updateWorkflow(workflowId, data);
|
||||
const workflow = await this.workflowsStore.updateWorkflow(workflowId, data);
|
||||
this.workflowsStore.setWorkflowVersionId(workflow.versionId);
|
||||
|
||||
if (isCurrentWorkflow) {
|
||||
|
@ -714,7 +713,7 @@ export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showM
|
|||
|
||||
workflowDataRequest.versionId = this.workflowsStore.workflowVersionId;
|
||||
|
||||
const workflowData = await this.restApi().updateWorkflow(
|
||||
const workflowData = await this.workflowsStore.updateWorkflow(
|
||||
currentWorkflow,
|
||||
workflowDataRequest,
|
||||
forceSave,
|
||||
|
@ -831,7 +830,7 @@ export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showM
|
|||
if (tags) {
|
||||
workflowDataRequest.tags = tags;
|
||||
}
|
||||
const workflowData = await this.restApi().createNewWorkflow(workflowDataRequest);
|
||||
const workflowData = await this.workflowsStore.createNewWorkflow(workflowDataRequest);
|
||||
|
||||
this.workflowsStore.addWorkflow(workflowData);
|
||||
|
||||
|
@ -944,7 +943,7 @@ export const workflowHelpers = mixins(externalHooks, nodeHelpers, restApi, showM
|
|||
async dataHasChanged(id: string) {
|
||||
const currentData = await this.getWorkflowDataToSave();
|
||||
|
||||
const data: IWorkflowDb = await this.restApi().getWorkflow(id);
|
||||
const data: IWorkflowDb = await this.workflowsStore.fetchWorkflow(id);
|
||||
|
||||
if (data !== undefined) {
|
||||
const x = {
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
|
||||
|
@ -20,7 +19,7 @@ import { useUIStore } from '@/stores/ui';
|
|||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
import { useRootStore } from '@/stores/n8nRootStore';
|
||||
|
||||
export const workflowRun = mixins(externalHooks, restApi, workflowHelpers, showMessage).extend({
|
||||
export const workflowRun = mixins(externalHooks, workflowHelpers, showMessage).extend({
|
||||
setup() {
|
||||
return {
|
||||
...useTitleChange(),
|
||||
|
@ -45,7 +44,7 @@ export const workflowRun = mixins(externalHooks, restApi, workflowHelpers, showM
|
|||
let response: IExecutionPushResponse;
|
||||
|
||||
try {
|
||||
response = await this.restApi().runWorkflow(runData);
|
||||
response = await this.workflowsStore.runWorkflow(runData);
|
||||
} catch (error) {
|
||||
this.uiStore.removeActiveAction('workflowRunning');
|
||||
throw error;
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
updateCredential,
|
||||
} from '@/api/credentials';
|
||||
import { setCredentialSharedWith } from '@/api/credentials.ee';
|
||||
import { getAppNameFromCredType } from '@/utils';
|
||||
import { getAppNameFromCredType, makeRestApiRequest } from '@/utils';
|
||||
import { EnterpriseEditionFeature, STORES } from '@/constants';
|
||||
import {
|
||||
ICredentialMap,
|
||||
|
@ -376,5 +376,15 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
|||
),
|
||||
);
|
||||
},
|
||||
|
||||
async getCredentialTranslation(credentialType: string): Promise<object> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'GET',
|
||||
'/credential-translation',
|
||||
{ credentialType },
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@ import { useRootStore } from './n8nRootStore';
|
|||
import { useUIStore } from './ui';
|
||||
import { useUsersStore } from './users';
|
||||
import { useVersionsStore } from './versions';
|
||||
import { makeRestApiRequest } from '@/utils';
|
||||
|
||||
export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||
state: (): ISettingsState => ({
|
||||
|
@ -340,5 +341,9 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
|||
setSaveManualExecutions(saveManualExecutions: boolean) {
|
||||
Vue.set(this, 'saveManualExecutions', saveManualExecutions);
|
||||
},
|
||||
async getTimezones(): Promise<IDataObject> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'GET', '/options/timezones');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -10,16 +10,23 @@ import {
|
|||
} from '@/constants';
|
||||
import {
|
||||
ExecutionsQueryFilter,
|
||||
IActivationError,
|
||||
IExecutionDeleteFilter,
|
||||
IExecutionPushResponse,
|
||||
IExecutionResponse,
|
||||
IExecutionsCurrentSummaryExtended,
|
||||
IExecutionsListResponse,
|
||||
IExecutionsStopData,
|
||||
INewWorkflowData,
|
||||
INodeUi,
|
||||
INodeUpdatePropertiesInformation,
|
||||
IPushDataExecutionFinished,
|
||||
IPushDataNodeExecuteAfter,
|
||||
IPushDataUnsavedExecutionFinished,
|
||||
IStartRunData,
|
||||
IUpdateInformation,
|
||||
IUsedCredential,
|
||||
IWorkflowDataUpdate,
|
||||
IWorkflowDb,
|
||||
IWorkflowsMap,
|
||||
WorkflowsState,
|
||||
|
@ -27,6 +34,7 @@ import {
|
|||
import { defineStore } from 'pinia';
|
||||
import {
|
||||
deepCopy,
|
||||
IAbstractEventMessage,
|
||||
IConnection,
|
||||
IConnections,
|
||||
IDataObject,
|
||||
|
@ -69,6 +77,8 @@ import {
|
|||
stringSizeInBytes,
|
||||
isObjectLiteral,
|
||||
isEmpty,
|
||||
makeRestApiRequest,
|
||||
unflattenExecutionData,
|
||||
} from '@/utils';
|
||||
import { useNDVStore } from './ndv';
|
||||
import { useNodeTypesStore } from './nodeTypes';
|
||||
|
@ -345,6 +355,19 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
return this.getWorkflow(nodes, connections, copyData);
|
||||
},
|
||||
|
||||
// Returns a workflow from a given URL
|
||||
async getWorkflowFromUrl(url: string): Promise<IWorkflowDb> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(rootStore.getRestApiContext, 'GET', '/workflows/from-url', {
|
||||
url,
|
||||
});
|
||||
},
|
||||
|
||||
async getActivationError(id: string): Promise<IActivationError | undefined> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'GET', `/active/error/${id}`);
|
||||
},
|
||||
|
||||
async fetchAllWorkflows(): Promise<IWorkflowDb[]> {
|
||||
const rootStore = useRootStore();
|
||||
const workflows = await getWorkflows(rootStore.getRestApiContext);
|
||||
|
@ -352,7 +375,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
return workflows;
|
||||
},
|
||||
|
||||
async fetchWorkflow(id: string): Promise<IWorkflowDb> {
|
||||
async fetchAndSetWorkflow(id: string): Promise<IWorkflowDb> {
|
||||
const rootStore = useRootStore();
|
||||
const workflow = await getWorkflow(rootStore.getRestApiContext, id);
|
||||
this.addWorkflow(workflow);
|
||||
|
@ -1025,6 +1048,144 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
Vue.set(this, 'activeExecutions', newActiveExecutions);
|
||||
},
|
||||
|
||||
async retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean> {
|
||||
let sendData;
|
||||
if (loadWorkflow === true) {
|
||||
sendData = {
|
||||
loadWorkflow: true,
|
||||
};
|
||||
}
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'POST',
|
||||
`/executions/${id}/retry`,
|
||||
sendData,
|
||||
);
|
||||
},
|
||||
|
||||
// Deletes executions
|
||||
async deleteExecutions(sendData: IExecutionDeleteFilter): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'POST',
|
||||
'/executions/delete',
|
||||
sendData as unknown as IDataObject,
|
||||
);
|
||||
},
|
||||
|
||||
// TODO: For sure needs some kind of default filter like last day, with max 10 results, ...
|
||||
async getPastExecutions(
|
||||
filter: IDataObject,
|
||||
limit: number,
|
||||
lastId?: string,
|
||||
firstId?: string,
|
||||
): Promise<IExecutionsListResponse> {
|
||||
let sendData = {};
|
||||
if (filter) {
|
||||
sendData = {
|
||||
filter,
|
||||
firstId,
|
||||
lastId,
|
||||
limit,
|
||||
};
|
||||
}
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'GET', '/executions', sendData);
|
||||
},
|
||||
|
||||
async getCurrentExecutions(filter: IDataObject): Promise<IExecutionsCurrentSummaryExtended[]> {
|
||||
let sendData = {};
|
||||
if (filter) {
|
||||
sendData = {
|
||||
filter,
|
||||
};
|
||||
}
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'GET',
|
||||
'/executions-current',
|
||||
sendData,
|
||||
);
|
||||
},
|
||||
|
||||
async getExecution(id: string): Promise<IExecutionResponse | undefined> {
|
||||
const rootStore = useRootStore();
|
||||
const response = await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'GET',
|
||||
`/executions/${id}`,
|
||||
);
|
||||
return response && unflattenExecutionData(response);
|
||||
},
|
||||
|
||||
async fetchWorkflow(id: string): Promise<IWorkflowDb> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'GET', `/workflows/${id}`);
|
||||
},
|
||||
|
||||
// Creates a new workflow
|
||||
async createNewWorkflow(sendData: IWorkflowDataUpdate): Promise<IWorkflowDb> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'POST',
|
||||
'/workflows',
|
||||
sendData as unknown as IDataObject,
|
||||
);
|
||||
},
|
||||
|
||||
// Deletes a workflow
|
||||
async deleteWorkflowAPI(name: string): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'DELETE', `/workflows/${name}`);
|
||||
},
|
||||
|
||||
// Updates an existing workflow
|
||||
async updateWorkflow(
|
||||
id: string,
|
||||
data: IWorkflowDataUpdate,
|
||||
forceSave = false,
|
||||
): Promise<IWorkflowDb> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'PATCH',
|
||||
`/workflows/${id}${forceSave ? '?forceSave=true' : ''}`,
|
||||
data as unknown as IDataObject,
|
||||
);
|
||||
},
|
||||
|
||||
async runWorkflow(startRunData: IStartRunData): Promise<IExecutionPushResponse> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'POST',
|
||||
'/workflows/run',
|
||||
startRunData as unknown as IDataObject,
|
||||
);
|
||||
},
|
||||
|
||||
async removeTestWebhook(workflowId: string): Promise<boolean> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'DELETE',
|
||||
`/test-webhook/${workflowId}`,
|
||||
);
|
||||
},
|
||||
|
||||
async stopCurrentExecution(executionId: string): Promise<IExecutionsStopData> {
|
||||
const rootStore = useRootStore();
|
||||
return await makeRestApiRequest(
|
||||
rootStore.getRestApiContext,
|
||||
'POST',
|
||||
`/executions-current/${executionId}/stop`,
|
||||
);
|
||||
},
|
||||
|
||||
async loadCurrentWorkflowExecutions(
|
||||
requestFilter: ExecutionsQueryFilter,
|
||||
): Promise<IExecutionsSummary[]> {
|
||||
|
@ -1047,13 +1208,16 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
async fetchExecutionDataById(executionId: string): Promise<IExecutionResponse | null> {
|
||||
const rootStore = useRootStore();
|
||||
return await getExecutionData(rootStore.getRestApiContext, executionId);
|
||||
},
|
||||
|
||||
deleteExecution(execution: IExecutionsSummary): void {
|
||||
this.currentWorkflowExecutions.splice(this.currentWorkflowExecutions.indexOf(execution), 1);
|
||||
},
|
||||
|
||||
addToCurrentExecutions(executions: IExecutionsSummary[]): void {
|
||||
executions.forEach((execution) => {
|
||||
const exists = this.currentWorkflowExecutions.find((ex) => ex.id === execution.id);
|
||||
|
@ -1062,6 +1226,23 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
}
|
||||
});
|
||||
},
|
||||
// Returns all the available timezones
|
||||
async getExecutionEvents(id: string): Promise<IAbstractEventMessage[]> {
|
||||
const rootStore = useRootStore();
|
||||
return makeRestApiRequest(rootStore.getRestApiContext, 'GET', '/eventbus/execution/' + id);
|
||||
},
|
||||
// Binary data
|
||||
async getBinaryUrl(dataPath, mode, fileName, mimeType): string {
|
||||
const rootStore = useRootStore();
|
||||
let restUrl = rootStore.getRestUrl;
|
||||
if (restUrl.startsWith('/')) restUrl = window.location.origin + restUrl;
|
||||
const url = new URL(`${restUrl}/data/${dataPath}`);
|
||||
url.searchParams.append('mode', mode);
|
||||
if (fileName) url.searchParams.append('fileName', fileName);
|
||||
if (mimeType) url.searchParams.append('mimeType', mimeType);
|
||||
return url.toString();
|
||||
},
|
||||
|
||||
setNodePristine(nodeName: string, isPristine: boolean): void {
|
||||
Vue.set(this.nodeMetadata[nodeName], 'pristine', isPristine);
|
||||
},
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import axios, { AxiosRequestConfig, Method } from 'axios';
|
||||
import { IDataObject } from 'n8n-workflow';
|
||||
import type { IRestApiContext } from '@/Interface';
|
||||
import type {
|
||||
IExecutionFlattedResponse,
|
||||
IExecutionResponse,
|
||||
IRestApiContext,
|
||||
IWorkflowDb,
|
||||
} from '@/Interface';
|
||||
import { parse } from 'flatted';
|
||||
|
||||
export const NO_NETWORK_ERROR_CODE = 999;
|
||||
|
||||
|
@ -127,3 +133,27 @@ export async function post(
|
|||
) {
|
||||
return await request({ method: 'POST', baseURL, endpoint, headers, data: params });
|
||||
}
|
||||
|
||||
/**
|
||||
* Unflattens the Execution data.
|
||||
*
|
||||
* @param {IExecutionFlattedResponse} fullExecutionData The data to unflatten
|
||||
*/
|
||||
export function unflattenExecutionData(
|
||||
fullExecutionData: IExecutionFlattedResponse,
|
||||
): IExecutionResponse {
|
||||
// Unflatten the data
|
||||
const returnData: IExecutionResponse = {
|
||||
...fullExecutionData,
|
||||
workflowData: fullExecutionData.workflowData as IWorkflowDb,
|
||||
data: parse(fullExecutionData.data),
|
||||
};
|
||||
|
||||
returnData.finished = returnData.finished ? returnData.finished : false;
|
||||
|
||||
if (fullExecutionData.id) {
|
||||
returnData.id = fullExecutionData.id;
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
|
|
@ -205,7 +205,6 @@ import { copyPaste } from '@/mixins/copyPaste';
|
|||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { moveNodeWorkflow } from '@/mixins/moveNodeWorkflow';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import useGlobalLinkActions from '@/composables/useGlobalLinkActions';
|
||||
import useCanvasMouseSelect from '@/composables/useCanvasMouseSelect';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
|
@ -322,7 +321,6 @@ export default mixins(
|
|||
externalHooks,
|
||||
genericHelpers,
|
||||
moveNodeWorkflow,
|
||||
restApi,
|
||||
showMessage,
|
||||
workflowHelpers,
|
||||
workflowRun,
|
||||
|
@ -783,7 +781,7 @@ export default mixins(
|
|||
this.resetWorkspace();
|
||||
let data: IExecutionResponse | undefined;
|
||||
try {
|
||||
data = await this.restApi().getExecution(executionId);
|
||||
data = await this.workflowsStore.getExecution(executionId);
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('nodeView.showError.openExecution.title'));
|
||||
return;
|
||||
|
@ -1403,14 +1401,14 @@ export default mixins(
|
|||
|
||||
try {
|
||||
this.stopExecutionInProgress = true;
|
||||
await this.restApi().stopCurrentExecution(executionId);
|
||||
await this.workflowsStore.stopCurrentExecution(executionId);
|
||||
this.$showMessage({
|
||||
title: this.$locale.baseText('nodeView.showMessage.stopExecutionTry.title'),
|
||||
type: 'success',
|
||||
});
|
||||
} catch (error) {
|
||||
// Execution stop might fail when the execution has already finished. Let's treat this here.
|
||||
const execution = await this.restApi().getExecution(executionId);
|
||||
const execution = await this.workflowsStore.getExecution(executionId);
|
||||
|
||||
if (execution === undefined) {
|
||||
// execution finished but was not saved (e.g. due to low connectivity)
|
||||
|
@ -1476,7 +1474,7 @@ export default mixins(
|
|||
|
||||
async stopWaitingForWebhook() {
|
||||
try {
|
||||
await this.restApi().removeTestWebhook(this.workflowsStore.workflowId);
|
||||
await this.workflowsStore.removeTestWebhook(this.workflowsStore.workflowId);
|
||||
} catch (error) {
|
||||
this.$showError(
|
||||
error,
|
||||
|
@ -1549,7 +1547,7 @@ export default mixins(
|
|||
|
||||
this.startLoading();
|
||||
try {
|
||||
workflowData = await this.restApi().getWorkflowFromUrl(url);
|
||||
workflowData = await this.workflowsStore.getWorkflowFromUrl(url);
|
||||
} catch (error) {
|
||||
this.stopLoading();
|
||||
this.$showError(
|
||||
|
@ -2586,7 +2584,7 @@ export default mixins(
|
|||
if (workflowId !== null) {
|
||||
let workflow: IWorkflowDb | undefined = undefined;
|
||||
try {
|
||||
workflow = await this.restApi().getWorkflow(workflowId);
|
||||
workflow = await this.workflowsStore.fetchWorkflow(workflowId);
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('openWorkflow.workflowNotFoundError'));
|
||||
|
||||
|
@ -3586,8 +3584,7 @@ export default mixins(
|
|||
return Promise.resolve();
|
||||
},
|
||||
async loadActiveWorkflows(): Promise<void> {
|
||||
const activeWorkflows = await this.restApi().getActiveWorkflows();
|
||||
this.workflowsStore.activeWorkflows = activeWorkflows;
|
||||
await this.workflowsStore.fetchActiveWorkflows();
|
||||
},
|
||||
async loadNodeTypes(): Promise<void> {
|
||||
await this.nodeTypesStore.getNodeTypes();
|
||||
|
|
|
@ -14,16 +14,14 @@ import { showMessage } from '@/mixins/showMessage';
|
|||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { IFormBoxConfig } from '@/Interface';
|
||||
import { VIEWS, ASSUMPTION_EXPERIMENT } from '@/constants';
|
||||
import { restApi } from '@/mixins/restApi';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
import { useCredentialsStore } from '@/stores/credentials';
|
||||
import { usePostHog } from '@/stores/posthog';
|
||||
|
||||
export default mixins(showMessage, restApi).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SetupView',
|
||||
components: {
|
||||
AuthView,
|
||||
|
|
Loading…
Reference in a new issue