mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
feat: Replace all Vue.set usages with direct assignment and spread operator (no-changelog) (#6280)
* refactor: replace all Vue.set usages with direct assignment and spread operator * chore: fix linting issue * fix: fix updateNodeAtIndex function * fix: various post-refactoring fixes * fix: refactor recently added Vue.set directive
This commit is contained in:
parent
c2afed4ca1
commit
596cf07e42
|
@ -29,7 +29,6 @@ describe('Canvas Node Manipulation and Navigation', () => {
|
|||
WorkflowPage.actions.visit();
|
||||
});
|
||||
|
||||
|
||||
it('should add switch node and test connections', () => {
|
||||
WorkflowPage.actions.addNodeToCanvas(SWITCH_NODE_NAME, true);
|
||||
|
||||
|
@ -114,7 +113,7 @@ describe('Canvas Node Manipulation and Navigation', () => {
|
|||
WorkflowPage.actions.zoomToFit();
|
||||
|
||||
cy.get('.plus-draggable-endpoint').filter(':visible').should('not.have.class', 'ep-success');
|
||||
cy.get('.jtk-connector.success').should('have.length', 3);
|
||||
cy.get('.jtk-connector.success').should('have.length', 4);
|
||||
cy.get('.jtk-connector').should('have.length', 4);
|
||||
});
|
||||
|
||||
|
|
|
@ -16,12 +16,10 @@ describe('Data mapping', () => {
|
|||
beforeEach(() => {
|
||||
workflowPage.actions.visit();
|
||||
|
||||
cy.window().then(
|
||||
(win) => {
|
||||
cy.window().then((win) => {
|
||||
// @ts-ignore
|
||||
win.preventNodeViewBeforeUnload = true;
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('maps expressions from table header', () => {
|
||||
|
@ -303,19 +301,28 @@ describe('Data mapping', () => {
|
|||
|
||||
ndv.getters.parameterInput('keepOnlySet').find('input[type="checkbox"]').should('exist');
|
||||
ndv.getters.parameterInput('keepOnlySet').find('input[type="text"]').should('not.exist');
|
||||
ndv.getters.inputDataContainer().should('exist').find('span').contains('count').realMouseDown().realMouseMove(100, 100);
|
||||
ndv.getters
|
||||
.inputDataContainer()
|
||||
.should('exist')
|
||||
.find('span')
|
||||
.contains('count')
|
||||
.realMouseDown()
|
||||
.realMouseMove(100, 100);
|
||||
cy.wait(50);
|
||||
|
||||
ndv.getters.parameterInput('keepOnlySet').find('input[type="checkbox"]').should('not.exist');
|
||||
ndv.getters.parameterInput('keepOnlySet').find('input[type="text"]')
|
||||
ndv.getters
|
||||
.parameterInput('keepOnlySet')
|
||||
.find('input[type="text"]')
|
||||
.should('exist')
|
||||
.invoke('css', 'border')
|
||||
.then((border) => expect(border).to.include('dashed rgb(90, 76, 194)'));
|
||||
|
||||
ndv.getters.parameterInput('value').find('input[type="text"]')
|
||||
ndv.getters
|
||||
.parameterInput('value')
|
||||
.find('input[type="text"]')
|
||||
.should('exist')
|
||||
.invoke('css', 'border')
|
||||
.then((border) => expect(border).to.include('dashed rgb(90, 76, 194)'));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -13,14 +13,17 @@ export class NDV extends BasePage {
|
|||
outputPanel: () => cy.getByTestId('output-panel'),
|
||||
executingLoader: () => cy.getByTestId('ndv-executing'),
|
||||
inputDataContainer: () => this.getters.inputPanel().findChildByTestId('ndv-data-container'),
|
||||
inputDisplayMode: () => this.getters.inputPanel().findChildByTestId('ndv-run-data-display-mode').first(),
|
||||
inputDisplayMode: () =>
|
||||
this.getters.inputPanel().findChildByTestId('ndv-run-data-display-mode').first(),
|
||||
outputDataContainer: () => this.getters.outputPanel().findChildByTestId('ndv-data-container'),
|
||||
outputDisplayMode: () => this.getters.outputPanel().findChildByTestId('ndv-run-data-display-mode').first(),
|
||||
outputDisplayMode: () =>
|
||||
this.getters.outputPanel().findChildByTestId('ndv-run-data-display-mode').first(),
|
||||
pinDataButton: () => cy.getByTestId('ndv-pin-data'),
|
||||
editPinnedDataButton: () => cy.getByTestId('ndv-edit-pinned-data'),
|
||||
pinnedDataEditor: () => this.getters.outputPanel().find('.cm-editor .cm-scroller'),
|
||||
runDataPaneHeader: () => cy.getByTestId('run-data-pane-header'),
|
||||
savePinnedDataButton: () => this.getters.runDataPaneHeader().find('button').filter(':visible').contains('Save'),
|
||||
savePinnedDataButton: () =>
|
||||
this.getters.runDataPaneHeader().find('button').filter(':visible').contains('Save'),
|
||||
outputTableRows: () => this.getters.outputDataContainer().find('table tr'),
|
||||
outputTableHeaders: () => this.getters.outputDataContainer().find('table thead th'),
|
||||
outputTableRow: (row: number) => this.getters.outputTableRows().eq(row),
|
||||
|
@ -52,10 +55,13 @@ export class NDV extends BasePage {
|
|||
outputBranches: () => this.getters.outputPanel().findChildByTestId('branches'),
|
||||
inputBranches: () => this.getters.inputPanel().findChildByTestId('branches'),
|
||||
resourceLocator: (paramName: string) => cy.getByTestId(`resource-locator-${paramName}`),
|
||||
resourceLocatorInput: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="rlc-input-container"]'),
|
||||
resourceLocatorDropdown: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="resource-locator-dropdown"]'),
|
||||
resourceLocatorInput: (paramName: string) =>
|
||||
this.getters.resourceLocator(paramName).find('[data-test-id="rlc-input-container"]'),
|
||||
resourceLocatorDropdown: (paramName: string) =>
|
||||
this.getters.resourceLocator(paramName).find('[data-test-id="resource-locator-dropdown"]'),
|
||||
resourceLocatorErrorMessage: () => cy.getByTestId('rlc-error-container'),
|
||||
resourceLocatorModeSelector: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="rlc-mode-selector"]'),
|
||||
resourceLocatorModeSelector: (paramName: string) =>
|
||||
this.getters.resourceLocator(paramName).find('[data-test-id="rlc-mode-selector"]'),
|
||||
};
|
||||
|
||||
actions = {
|
||||
|
@ -82,7 +88,9 @@ export class NDV extends BasePage {
|
|||
this.getters.editPinnedDataButton().click();
|
||||
|
||||
this.getters.pinnedDataEditor().click();
|
||||
this.getters.pinnedDataEditor().type(`{selectall}{backspace}${JSON.stringify(data).replace(new RegExp('{', 'g'), '{{}')}`);
|
||||
this.getters
|
||||
.pinnedDataEditor()
|
||||
.type(`{selectall}{backspace}${JSON.stringify(data).replace(new RegExp('{', 'g'), '{{}')}`);
|
||||
|
||||
this.actions.savePinnedData();
|
||||
},
|
||||
|
@ -131,15 +139,11 @@ export class NDV extends BasePage {
|
|||
},
|
||||
changeInputRunSelector: (runName: string) => {
|
||||
this.getters.inputRunSelector().click();
|
||||
cy.get('.el-select-dropdown:visible .el-select-dropdown__item')
|
||||
.contains(runName)
|
||||
.click();
|
||||
cy.get('.el-select-dropdown:visible .el-select-dropdown__item').contains(runName).click();
|
||||
},
|
||||
changeOutputRunSelector: (runName: string) => {
|
||||
this.getters.outputRunSelector().click();
|
||||
cy.get('.el-select-dropdown:visible .el-select-dropdown__item')
|
||||
.contains(runName)
|
||||
.click();
|
||||
cy.get('.el-select-dropdown:visible .el-select-dropdown__item').contains(runName).click();
|
||||
},
|
||||
toggleOutputRunLinking: () => {
|
||||
this.getters.outputRunSelector().find('button').click();
|
||||
|
@ -159,7 +163,10 @@ export class NDV extends BasePage {
|
|||
this.getters.resourceLocatorInput(paramName).type(value);
|
||||
},
|
||||
validateExpressionPreview: (paramName: string, value: string) => {
|
||||
this.getters.parameterExpressionPreview(paramName).find('span').should('include.html', asEncodedHTML(value));
|
||||
this.getters
|
||||
.parameterExpressionPreview(paramName)
|
||||
.find('span')
|
||||
.should('include.html', asEncodedHTML(value));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -172,4 +179,3 @@ function asEncodedHTML(str: string): string {
|
|||
.replace(/"/g, '"')
|
||||
.replace(/ /g, ' ');
|
||||
}
|
||||
|
||||
|
|
|
@ -975,12 +975,9 @@ export interface ITagsState {
|
|||
fetchedUsageCount: boolean;
|
||||
}
|
||||
|
||||
export type Modals =
|
||||
| {
|
||||
[key: string]: ModalState;
|
||||
}
|
||||
| {
|
||||
export type Modals = {
|
||||
[CREDENTIAL_EDIT_MODAL_KEY]: NewCredentialsModal;
|
||||
[key: string]: ModalState;
|
||||
};
|
||||
|
||||
export type ModalState = {
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
} from '@/utils';
|
||||
import type { INodeProperties, INodeTypeDescription, NodeParameterValue } from 'n8n-workflow';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export interface Props {
|
||||
credentialType: Object;
|
||||
|
@ -27,7 +26,7 @@ const ndvStore = useNDVStore();
|
|||
const props = defineProps<Props>();
|
||||
|
||||
const selected = ref('');
|
||||
const authRelatedFieldsValues = ref({} as { [key: string]: NodeParameterValue });
|
||||
const authRelatedFieldsValues = ref<{ [key: string]: NodeParameterValue }>({});
|
||||
|
||||
onMounted(() => {
|
||||
if (activeNodeType.value?.credentials) {
|
||||
|
@ -43,7 +42,10 @@ onMounted(() => {
|
|||
|
||||
// Populate default values of related fields
|
||||
authRelatedFields.value.forEach((field) => {
|
||||
Vue.set(authRelatedFieldsValues.value, field.name, field.default);
|
||||
authRelatedFieldsValues.value = {
|
||||
...authRelatedFieldsValues.value,
|
||||
[field.name]: field.default as NodeParameterValue,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -102,7 +104,10 @@ function onAuthTypeChange(newType: string): void {
|
|||
}
|
||||
|
||||
function valueChanged(data: IUpdateInformation): void {
|
||||
Vue.set(authRelatedFieldsValues.value, data.name, data.value);
|
||||
authRelatedFieldsValues.value = {
|
||||
...authRelatedFieldsValues.value,
|
||||
[data.name]: data.value as NodeParameterValue,
|
||||
};
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
|
|
@ -264,7 +264,7 @@ export default defineComponent({
|
|||
);
|
||||
},
|
||||
credentialTypeName(): string {
|
||||
return (this.credentialType as ICredentialType).name;
|
||||
return (this.credentialType as ICredentialType)?.name;
|
||||
},
|
||||
credentialOwnerName(): string {
|
||||
return this.credentialsStore.getCredentialOwnerNameById(`${this.credentialId}`);
|
||||
|
|
|
@ -109,7 +109,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
|
@ -234,12 +233,15 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
if (this.currentUser) {
|
||||
Vue.set(this.credentialData, 'ownedBy', {
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
ownedBy: {
|
||||
id: this.currentUser.id,
|
||||
firstName: this.currentUser.firstName,
|
||||
lastName: this.currentUser.lastName,
|
||||
email: this.currentUser.email,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
} else {
|
||||
await this.loadCurrentCredential();
|
||||
|
@ -251,7 +253,10 @@ export default defineComponent({
|
|||
!this.credentialData.hasOwnProperty(property.name) &&
|
||||
!this.credentialType.__overwrittenProperties?.includes(property.name)
|
||||
) {
|
||||
Vue.set(this.credentialData, property.name, property.default as CredentialInformation);
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
[property.name]: property.default as CredentialInformation,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -594,12 +599,18 @@ export default defineComponent({
|
|||
);
|
||||
}
|
||||
|
||||
this.credentialData = currentCredentials.data || {};
|
||||
this.credentialData = (currentCredentials.data as ICredentialDataDecryptedObject) || {};
|
||||
if (currentCredentials.sharedWith) {
|
||||
Vue.set(this.credentialData, 'sharedWith', currentCredentials.sharedWith);
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
sharedWith: currentCredentials.sharedWith as IDataObject[],
|
||||
};
|
||||
}
|
||||
if (currentCredentials.ownedBy) {
|
||||
Vue.set(this.credentialData, 'ownedBy', currentCredentials.ownedBy);
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
ownedBy: currentCredentials.ownedBy as IDataObject[],
|
||||
};
|
||||
}
|
||||
|
||||
this.credentialName = currentCredentials.name;
|
||||
|
@ -650,7 +661,10 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
onChangeSharedWith(sharees: IDataObject[]) {
|
||||
Vue.set(this.credentialData, 'sharedWith', sharees);
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
sharedWith: sharees,
|
||||
};
|
||||
this.hasUnsavedChanges = true;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -997,7 +1011,11 @@ export default defineComponent({
|
|||
const params =
|
||||
'scrollbars=no,resizable=yes,status=no,titlebar=noe,location=no,toolbar=no,menubar=no,width=500,height=700';
|
||||
const oauthPopup = window.open(url, 'OAuth2 Authorization', params);
|
||||
Vue.set(this.credentialData, 'oauthTokenData', null);
|
||||
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
oauthTokenData: null as unknown as CredentialInformation,
|
||||
};
|
||||
|
||||
const receiveMessage = (event: MessageEvent) => {
|
||||
// // TODO: Add check that it came from n8n
|
||||
|
@ -1009,7 +1027,11 @@ export default defineComponent({
|
|||
|
||||
// Set some kind of data that status changes.
|
||||
// As data does not get displayed directly it does not matter what data.
|
||||
Vue.set(this.credentialData, 'oauthTokenData', {});
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
oauthTokenData: {} as CredentialInformation,
|
||||
};
|
||||
|
||||
this.credentialsStore.enableOAuthCredential(credential);
|
||||
|
||||
// Close the window
|
||||
|
@ -1061,7 +1083,10 @@ export default defineComponent({
|
|||
}
|
||||
for (const property of this.credentialType.properties) {
|
||||
if (!this.credentialType.__overwrittenProperties?.includes(property.name)) {
|
||||
Vue.set(this.credentialData, property.name, property.default as CredentialInformation);
|
||||
this.credentialData = {
|
||||
...this.credentialData,
|
||||
[property.name]: property.default as CredentialInformation,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -432,7 +432,7 @@ export default defineComponent({
|
|||
this.allVisibleSelected = !this.allVisibleSelected;
|
||||
if (!this.allVisibleSelected) {
|
||||
this.allExistingSelected = false;
|
||||
Vue.set(this, 'selectedItems', {});
|
||||
this.selectedItems = {};
|
||||
} else {
|
||||
this.selectAllVisibleExecutions();
|
||||
}
|
||||
|
@ -441,7 +441,10 @@ export default defineComponent({
|
|||
if (this.selectedItems[executionId]) {
|
||||
Vue.delete(this.selectedItems, executionId);
|
||||
} else {
|
||||
Vue.set(this.selectedItems, executionId, true);
|
||||
this.selectedItems = {
|
||||
...this.selectedItems,
|
||||
[executionId]: true,
|
||||
};
|
||||
}
|
||||
this.allVisibleSelected =
|
||||
Object.keys(this.selectedItems).length === this.combinedExecutions.length;
|
||||
|
@ -502,7 +505,7 @@ export default defineComponent({
|
|||
handleClearSelection(): void {
|
||||
this.allVisibleSelected = false;
|
||||
this.allExistingSelected = false;
|
||||
Vue.set(this, 'selectedItems', {});
|
||||
this.selectedItems = {};
|
||||
},
|
||||
async onFilterChanged(filter: ExecutionFilterType) {
|
||||
this.filter = filter;
|
||||
|
@ -635,7 +638,7 @@ export default defineComponent({
|
|||
this.finishedExecutionsCount = pastExecutions.count;
|
||||
this.finishedExecutionsCountEstimated = pastExecutions.estimated;
|
||||
|
||||
Vue.set(this, 'finishedExecutions', alreadyPresentExecutionsFiltered);
|
||||
this.finishedExecutions = alreadyPresentExecutionsFiltered;
|
||||
this.workflowsStore.addToCurrentExecutions(alreadyPresentExecutionsFiltered);
|
||||
|
||||
this.adjustSelectionAfterMoreItemsLoaded();
|
||||
|
@ -706,7 +709,8 @@ export default defineComponent({
|
|||
},
|
||||
async loadWorkflows() {
|
||||
try {
|
||||
const workflows = await this.workflowsStore.fetchAllWorkflows();
|
||||
const workflows =
|
||||
(await this.workflowsStore.fetchAllWorkflows()) as IWorkflowShortResponse[];
|
||||
workflows.sort((a, b) => {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
||||
return -1;
|
||||
|
@ -717,13 +721,12 @@ export default defineComponent({
|
|||
return 0;
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
workflows.unshift({
|
||||
id: 'all',
|
||||
name: this.$locale.baseText('executionsList.allWorkflows'),
|
||||
});
|
||||
} as IWorkflowShortResponse);
|
||||
|
||||
Vue.set(this, 'workflows', workflows);
|
||||
this.workflows = workflows;
|
||||
} catch (error) {
|
||||
this.showError(
|
||||
error,
|
||||
|
@ -900,7 +903,7 @@ export default defineComponent({
|
|||
await this.refreshData();
|
||||
|
||||
if (this.allVisibleSelected) {
|
||||
Vue.set(this, 'selectedItems', {});
|
||||
this.selectedItems = {};
|
||||
this.selectAllVisibleExecutions();
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -922,7 +925,7 @@ export default defineComponent({
|
|||
},
|
||||
selectAllVisibleExecutions() {
|
||||
this.combinedExecutions.forEach((execution: IExecutionsSummary) => {
|
||||
Vue.set(this.selectedItems, execution.id, true);
|
||||
this.selectedItems = { ...this.selectedItems, [execution.id]: true };
|
||||
});
|
||||
},
|
||||
adjustSelectionAfterMoreItemsLoaded() {
|
||||
|
|
|
@ -409,8 +409,8 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
activeNode(node: INodeUi | null) {
|
||||
if (node && !this.isActiveStickyNode) {
|
||||
activeNode(node: INodeUi | null, oldNode: INodeUi | null) {
|
||||
if (node && node.name !== oldNode?.name && !this.isActiveStickyNode) {
|
||||
this.runInputIndex = -1;
|
||||
this.runOutputIndex = -1;
|
||||
this.isLinkingEnabled = true;
|
||||
|
|
|
@ -533,8 +533,10 @@ export default defineComponent({
|
|||
Vue.delete(this.nodeValues, lastNamePart);
|
||||
} else {
|
||||
// Value should be set
|
||||
// @ts-ignore
|
||||
Vue.set(this.nodeValues, lastNamePart, value);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
[lastNamePart as string]: value,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Data is on lower level
|
||||
|
@ -556,14 +558,22 @@ export default defineComponent({
|
|||
} else {
|
||||
// Value should be set
|
||||
if (typeof value === 'object') {
|
||||
// @ts-ignore
|
||||
Vue.set(get(this.nodeValues, nameParts.join('.')), lastNamePart, deepCopy(value));
|
||||
set(
|
||||
get(this.nodeValues, nameParts.join('.')) as Record<string, unknown>,
|
||||
lastNamePart as string,
|
||||
deepCopy(value),
|
||||
);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
Vue.set(get(this.nodeValues, nameParts.join('.')), lastNamePart, value);
|
||||
set(
|
||||
get(this.nodeValues, nameParts.join('.')) as Record<string, unknown>,
|
||||
lastNamePart as string,
|
||||
value,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.nodeValues = { ...this.nodeValues };
|
||||
},
|
||||
credentialSelected(updateInformation: INodeUpdatePropertiesInformation) {
|
||||
// Update the values on the node
|
||||
|
@ -660,7 +670,7 @@ export default defineComponent({
|
|||
|
||||
if (Array.isArray(data)) {
|
||||
data.splice(parseInt(index, 10), 1);
|
||||
Vue.set(nodeParameters as object, path, data);
|
||||
set(nodeParameters as object, path, data);
|
||||
}
|
||||
} else {
|
||||
if (newValue === undefined) {
|
||||
|
@ -744,7 +754,7 @@ export default defineComponent({
|
|||
|
||||
if (Array.isArray(data)) {
|
||||
data.splice(parseInt(index, 10), 1);
|
||||
Vue.set(nodeParameters as object, path, data);
|
||||
set(nodeParameters as object, path, data);
|
||||
}
|
||||
} else {
|
||||
if (newValue === undefined) {
|
||||
|
@ -791,7 +801,10 @@ export default defineComponent({
|
|||
// A property on the node itself changed
|
||||
|
||||
// Update data in settings
|
||||
Vue.set(this.nodeValues, parameterData.name, newValue);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
[parameterData.name]: newValue,
|
||||
};
|
||||
|
||||
// Update data in vuex
|
||||
const updateInformation = {
|
||||
|
@ -818,58 +831,91 @@ export default defineComponent({
|
|||
const foundNodeSettings = [];
|
||||
if (this.node.color) {
|
||||
foundNodeSettings.push('color');
|
||||
Vue.set(this.nodeValues, 'color', this.node.color);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
color: this.node.color,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.notes) {
|
||||
foundNodeSettings.push('notes');
|
||||
Vue.set(this.nodeValues, 'notes', this.node.notes);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
notes: this.node.notes,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.alwaysOutputData) {
|
||||
foundNodeSettings.push('alwaysOutputData');
|
||||
Vue.set(this.nodeValues, 'alwaysOutputData', this.node.alwaysOutputData);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
alwaysOutputData: this.node.alwaysOutputData,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.executeOnce) {
|
||||
foundNodeSettings.push('executeOnce');
|
||||
Vue.set(this.nodeValues, 'executeOnce', this.node.executeOnce);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
executeOnce: this.node.executeOnce,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.continueOnFail) {
|
||||
foundNodeSettings.push('continueOnFail');
|
||||
Vue.set(this.nodeValues, 'continueOnFail', this.node.continueOnFail);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
continueOnFail: this.node.continueOnFail,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.notesInFlow) {
|
||||
foundNodeSettings.push('notesInFlow');
|
||||
Vue.set(this.nodeValues, 'notesInFlow', this.node.notesInFlow);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
notesInFlow: this.node.notesInFlow,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.retryOnFail) {
|
||||
foundNodeSettings.push('retryOnFail');
|
||||
Vue.set(this.nodeValues, 'retryOnFail', this.node.retryOnFail);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
retryOnFail: this.node.retryOnFail,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.maxTries) {
|
||||
foundNodeSettings.push('maxTries');
|
||||
Vue.set(this.nodeValues, 'maxTries', this.node.maxTries);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
maxTries: this.node.maxTries,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.node.waitBetweenTries) {
|
||||
foundNodeSettings.push('waitBetweenTries');
|
||||
Vue.set(this.nodeValues, 'waitBetweenTries', this.node.waitBetweenTries);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
waitBetweenTries: this.node.waitBetweenTries,
|
||||
};
|
||||
}
|
||||
|
||||
// Set default node settings
|
||||
for (const nodeSetting of this.nodeSettings) {
|
||||
if (!foundNodeSettings.includes(nodeSetting.name)) {
|
||||
// Set default value
|
||||
Vue.set(this.nodeValues, nodeSetting.name, nodeSetting.default);
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
[nodeSetting.name]: nodeSetting.default,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Vue.set(this.nodeValues, 'parameters', deepCopy(this.node.parameters));
|
||||
this.nodeValues = {
|
||||
...this.nodeValues,
|
||||
parameters: deepCopy(this.node.parameters),
|
||||
};
|
||||
} else {
|
||||
this.nodeValid = false;
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ import {
|
|||
defaultMessageEventBusDestinationSentryOptions,
|
||||
} from 'n8n-workflow';
|
||||
import type { PropType } from 'vue';
|
||||
import Vue, { defineComponent } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { LOG_STREAM_MODAL_KEY, MODAL_CONFIRM } from '@/constants';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
import { useMessage } from '@/composables';
|
||||
|
@ -249,7 +249,9 @@ export default defineComponent({
|
|||
showRemoveConfirm: false,
|
||||
typeSelectValue: '',
|
||||
typeSelectPlaceholder: 'Destination Type',
|
||||
nodeParameters: deepCopy(defaultMessageEventBusDestinationOptions),
|
||||
nodeParameters: deepCopy(
|
||||
defaultMessageEventBusDestinationOptions,
|
||||
) as MessageEventBusDestinationOptions,
|
||||
webhookDescription: webhookModalDescription,
|
||||
sentryDescription: sentryModalDescription,
|
||||
syslogDescription: syslogModalDescription,
|
||||
|
@ -400,13 +402,13 @@ export default defineComponent({
|
|||
// Apply the new value
|
||||
if (parameterData.value === undefined && parameterPathArray !== null) {
|
||||
// Delete array item
|
||||
const path = parameterPathArray[1];
|
||||
const path = parameterPathArray[1] as keyof MessageEventBusDestinationOptions;
|
||||
const index = parameterPathArray[2];
|
||||
const data = get(nodeParameters, path);
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
data.splice(parseInt(index, 10), 1);
|
||||
Vue.set(nodeParameters, path, data);
|
||||
nodeParameters[path] = data as never;
|
||||
}
|
||||
} else {
|
||||
if (newValue === undefined) {
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, { defineComponent } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import type { ITag } from '@/Interface';
|
||||
import IntersectionObserver from './IntersectionObserver.vue';
|
||||
|
@ -109,7 +109,7 @@ export default defineComponent({
|
|||
methods: {
|
||||
onObserved({ el, isIntersecting }: { el: HTMLElement; isIntersecting: boolean }) {
|
||||
if (el.dataset.id) {
|
||||
Vue.set(this.$data.visibility, el.dataset.id, isIntersecting);
|
||||
this.$data.visibility = { ...this.$data.visibility, [el.dataset.id]: isIntersecting };
|
||||
}
|
||||
},
|
||||
onClick(e: MouseEvent, tag: TagEl) {
|
||||
|
|
|
@ -337,7 +337,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
|
@ -537,7 +536,7 @@ export default defineComponent({
|
|||
workflowSettings.maxExecutionTimeout = this.rootStore.maxExecutionTimeout;
|
||||
}
|
||||
|
||||
Vue.set(this, 'workflowSettings', workflowSettings);
|
||||
this.workflowSettings = workflowSettings;
|
||||
this.timeoutHMS = this.convertToHMS(workflowSettings.executionTimeout);
|
||||
this.isLoading = false;
|
||||
|
||||
|
@ -752,7 +751,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
async loadWorkflows() {
|
||||
const workflows = await this.workflowsStore.fetchAllWorkflows();
|
||||
const workflows = (await this.workflowsStore.fetchAllWorkflows()) as IWorkflowShortResponse[];
|
||||
workflows.sort((a, b) => {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
||||
return -1;
|
||||
|
@ -763,13 +762,12 @@ export default defineComponent({
|
|||
return 0;
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
workflows.unshift({
|
||||
id: undefined as unknown as string,
|
||||
name: this.$locale.baseText('workflowSettings.noWorkflow'),
|
||||
});
|
||||
} as IWorkflowShortResponse);
|
||||
|
||||
Vue.set(this, 'workflows', workflows);
|
||||
this.workflows = workflows;
|
||||
},
|
||||
async saveSettings() {
|
||||
// Set that the active state should be changed
|
||||
|
|
|
@ -220,10 +220,13 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
|||
},
|
||||
upsertCredential(credential: ICredentialsResponse): void {
|
||||
if (credential.id) {
|
||||
Vue.set(this.credentials, credential.id, {
|
||||
this.credentials = {
|
||||
...this.credentials,
|
||||
[credential.id]: {
|
||||
...this.credentials[credential.id],
|
||||
...credential,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
enableOAuthCredential(credential: ICredentialsResponse): void {
|
||||
|
@ -351,31 +354,38 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
|||
|
||||
// Enterprise edition actions
|
||||
setCredentialOwnedBy(payload: { credentialId: string; ownedBy: Partial<IUser> }) {
|
||||
Vue.set(this.credentials[payload.credentialId], 'ownedBy', payload.ownedBy);
|
||||
this.credentials[payload.credentialId] = {
|
||||
...this.credentials[payload.credentialId],
|
||||
ownedBy: payload.ownedBy,
|
||||
};
|
||||
},
|
||||
async setCredentialSharedWith(payload: { sharedWith: IUser[]; credentialId: string }) {
|
||||
if (useSettingsStore().isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
await setCredentialSharedWith(useRootStore().getRestApiContext, payload.credentialId, {
|
||||
shareWithIds: payload.sharedWith.map((sharee) => sharee.id),
|
||||
});
|
||||
Vue.set(this.credentials[payload.credentialId], 'sharedWith', payload.sharedWith);
|
||||
|
||||
this.credentials[payload.credentialId] = {
|
||||
...this.credentials[payload.credentialId],
|
||||
sharedWith: payload.sharedWith,
|
||||
};
|
||||
}
|
||||
},
|
||||
addCredentialSharee(payload: { credentialId: string; sharee: Partial<IUser> }): void {
|
||||
Vue.set(
|
||||
this.credentials[payload.credentialId],
|
||||
'sharedWith',
|
||||
(this.credentials[payload.credentialId].sharedWith || []).concat([payload.sharee]),
|
||||
);
|
||||
this.credentials[payload.credentialId] = {
|
||||
...this.credentials[payload.credentialId],
|
||||
sharedWith: (this.credentials[payload.credentialId].sharedWith || []).concat([
|
||||
payload.sharee,
|
||||
]),
|
||||
};
|
||||
},
|
||||
removeCredentialSharee(payload: { credentialId: string; sharee: Partial<IUser> }): void {
|
||||
Vue.set(
|
||||
this.credentials[payload.credentialId],
|
||||
'sharedWith',
|
||||
(this.credentials[payload.credentialId].sharedWith || []).filter(
|
||||
this.credentials[payload.credentialId] = {
|
||||
...this.credentials[payload.credentialId],
|
||||
sharedWith: (this.credentials[payload.credentialId].sharedWith || []).filter(
|
||||
(sharee) => sharee.id !== payload.sharee.id,
|
||||
),
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
async getCredentialTranslation(credentialType: string): Promise<object> {
|
||||
|
|
|
@ -2,7 +2,6 @@ import { CLOUD_BASE_URL_PRODUCTION, CLOUD_BASE_URL_STAGING, STORES } from '@/con
|
|||
import type { IRestApiContext, RootState } from '@/Interface';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import { useNodeTypesStore } from './nodeTypes.store';
|
||||
|
||||
const { VUE_APP_URL_BASE_API } = import.meta.env;
|
||||
|
@ -76,44 +75,44 @@ export const useRootStore = defineStore(STORES.ROOT, {
|
|||
actions: {
|
||||
setUrlBaseWebhook(urlBaseWebhook: string): void {
|
||||
const url = urlBaseWebhook.endsWith('/') ? urlBaseWebhook : `${urlBaseWebhook}/`;
|
||||
Vue.set(this, 'urlBaseWebhook', url);
|
||||
this.urlBaseWebhook = url;
|
||||
},
|
||||
setUrlBaseEditor(urlBaseEditor: string): void {
|
||||
const url = urlBaseEditor.endsWith('/') ? urlBaseEditor : `${urlBaseEditor}/`;
|
||||
Vue.set(this, 'urlBaseEditor', url);
|
||||
this.urlBaseEditor = url;
|
||||
},
|
||||
setEndpointWebhook(endpointWebhook: string): void {
|
||||
Vue.set(this, 'endpointWebhook', endpointWebhook);
|
||||
this.endpointWebhook = endpointWebhook;
|
||||
},
|
||||
setEndpointWebhookTest(endpointWebhookTest: string): void {
|
||||
Vue.set(this, 'endpointWebhookTest', endpointWebhookTest);
|
||||
this.endpointWebhookTest = endpointWebhookTest;
|
||||
},
|
||||
setTimezone(timezone: string): void {
|
||||
Vue.set(this, 'timezone', timezone);
|
||||
this.timezone = timezone;
|
||||
},
|
||||
setExecutionTimeout(executionTimeout: number): void {
|
||||
Vue.set(this, 'executionTimeout', executionTimeout);
|
||||
this.executionTimeout = executionTimeout;
|
||||
},
|
||||
setMaxExecutionTimeout(maxExecutionTimeout: number): void {
|
||||
Vue.set(this, 'maxExecutionTimeout', maxExecutionTimeout);
|
||||
this.maxExecutionTimeout = maxExecutionTimeout;
|
||||
},
|
||||
setVersionCli(version: string): void {
|
||||
Vue.set(this, 'versionCli', version);
|
||||
this.versionCli = version;
|
||||
},
|
||||
setInstanceId(instanceId: string): void {
|
||||
Vue.set(this, 'instanceId', instanceId);
|
||||
this.instanceId = instanceId;
|
||||
},
|
||||
setOauthCallbackUrls(urls: IDataObject): void {
|
||||
Vue.set(this, 'oauthCallbackUrls', urls);
|
||||
this.oauthCallbackUrls = urls;
|
||||
},
|
||||
setN8nMetadata(metadata: IDataObject): void {
|
||||
Vue.set(this, 'n8nMetadata', metadata);
|
||||
this.n8nMetadata = metadata as RootState['n8nMetadata'];
|
||||
},
|
||||
setDefaultLocale(locale: string): void {
|
||||
Vue.set(this, 'defaultLocale', locale);
|
||||
this.defaultLocale = locale;
|
||||
},
|
||||
setIsNpmAvailable(isNpmAvailable: boolean): void {
|
||||
Vue.set(this, 'isNpmAvailable', isNpmAvailable);
|
||||
this.isNpmAvailable = isNpmAvailable;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import type {
|
|||
} from '@/Interface';
|
||||
import type { INodeIssues, IRunData } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import { useWorkflowsStore } from './workflows.store';
|
||||
|
||||
export const useNDVStore = defineStore(STORES.NDV, {
|
||||
|
@ -128,38 +127,47 @@ export const useNDVStore = defineStore(STORES.NDV, {
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
setInputNodeName(name: string | undefined): void {
|
||||
Vue.set(this.input, 'nodeName', name);
|
||||
setInputNodeName(nodeName: string | undefined): void {
|
||||
this.input = {
|
||||
...this.input,
|
||||
nodeName,
|
||||
};
|
||||
},
|
||||
setInputRunIndex(run?: string): void {
|
||||
Vue.set(this.input, 'run', run);
|
||||
setInputRunIndex(run?: number): void {
|
||||
this.input = {
|
||||
...this.input,
|
||||
run,
|
||||
};
|
||||
},
|
||||
setMainPanelDimensions(params: {
|
||||
panelType: string;
|
||||
dimensions: { relativeLeft?: number; relativeRight?: number; relativeWidth?: number };
|
||||
}): void {
|
||||
Vue.set(this.mainPanelDimensions, params.panelType, {
|
||||
this.mainPanelDimensions = {
|
||||
...this.mainPanelDimensions,
|
||||
[params.panelType]: {
|
||||
...this.mainPanelDimensions[params.panelType],
|
||||
...params.dimensions,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
setNDVSessionId(): void {
|
||||
Vue.set(this, 'sessionId', `ndv-${Math.random().toString(36).slice(-8)}`);
|
||||
this.sessionId = `ndv-${Math.random().toString(36).slice(-8)}`;
|
||||
},
|
||||
resetNDVSessionId(): void {
|
||||
Vue.set(this, 'sessionId', '');
|
||||
this.sessionId = '';
|
||||
},
|
||||
setPanelDisplayMode(params: { pane: NodePanelType; mode: IRunDataDisplayMode }): void {
|
||||
Vue.set(this[params.pane], 'displayMode', params.mode);
|
||||
this[params.pane].displayMode = params.mode;
|
||||
},
|
||||
setOutputPanelEditModeEnabled(isEnabled: boolean): void {
|
||||
Vue.set(this.output.editMode, 'enabled', isEnabled);
|
||||
this.output.editMode.enabled = isEnabled;
|
||||
},
|
||||
setOutputPanelEditModeValue(payload: string): void {
|
||||
Vue.set(this.output.editMode, 'value', payload);
|
||||
this.output.editMode.value = payload;
|
||||
},
|
||||
setMappableNDVInputFocus(paramName: string): void {
|
||||
Vue.set(this, 'focusedMappableInput', paramName);
|
||||
this.focusedMappableInput = paramName;
|
||||
},
|
||||
draggableStartDragging({ type, data }: { type: string; data: string }): void {
|
||||
this.draggable = {
|
||||
|
@ -180,10 +188,10 @@ export const useNDVStore = defineStore(STORES.NDV, {
|
|||
};
|
||||
},
|
||||
setDraggableStickyPos(position: XYPosition | null): void {
|
||||
Vue.set(this.draggable, 'stickyPosition', position);
|
||||
this.draggable.stickyPosition = position;
|
||||
},
|
||||
setDraggableCanDrop(canDrop: boolean): void {
|
||||
Vue.set(this.draggable, 'canDrop', canDrop);
|
||||
this.draggable.canDrop = canDrop;
|
||||
},
|
||||
setMappingTelemetry(telemetry: { [key: string]: string | number | boolean }): void {
|
||||
this.mappingTelemetry = { ...this.mappingTelemetry, ...telemetry };
|
||||
|
@ -192,13 +200,13 @@ export const useNDVStore = defineStore(STORES.NDV, {
|
|||
this.mappingTelemetry = {};
|
||||
},
|
||||
setHoveringItem(item: null | NDVState['hoveringItem']): void {
|
||||
Vue.set(this, 'hoveringItem', item);
|
||||
this.hoveringItem = item;
|
||||
},
|
||||
setNDVBranchIndex(e: { pane: 'input' | 'output'; branchIndex: number }): void {
|
||||
Vue.set(this[e.pane], 'branch', e.branchIndex);
|
||||
this[e.pane].branch = e.branchIndex;
|
||||
},
|
||||
setNDVPanelDataIsEmpty(payload: { panel: 'input' | 'output'; isEmpty: boolean }): void {
|
||||
Vue.set(this[payload.panel].data, 'isEmpty', payload.isEmpty);
|
||||
this[payload.panel].data.isEmpty = payload.isEmpty;
|
||||
},
|
||||
disableMappingHint(store = true) {
|
||||
this.isMappingOnboarded = true;
|
||||
|
@ -207,11 +215,19 @@ export const useNDVStore = defineStore(STORES.NDV, {
|
|||
}
|
||||
},
|
||||
updateNodeParameterIssues(issues: INodeIssues): void {
|
||||
const activeNode = this.activeNode;
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const activeNode = workflowsStore.getNodeByName(this.activeNodeName || '');
|
||||
|
||||
if (activeNode) {
|
||||
Vue.set(activeNode, 'issues', {
|
||||
const nodeIndex = workflowsStore.workflow.nodes.findIndex((node) => {
|
||||
return node.name === activeNode.name;
|
||||
});
|
||||
|
||||
workflowsStore.updateNodeAtIndex(nodeIndex, {
|
||||
issues: {
|
||||
...activeNode.issues,
|
||||
...issues,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -25,7 +25,6 @@ import type {
|
|||
ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import { useCredentialsStore } from './credentials.store';
|
||||
import { useRootStore } from './n8nRoot.store';
|
||||
|
||||
|
@ -120,7 +119,7 @@ export const useNodeTypesStore = defineStore(STORES.NODE_TYPES, {
|
|||
},
|
||||
{ ...this.nodeTypes },
|
||||
);
|
||||
Vue.set(this, 'nodeTypes', nodeTypes);
|
||||
this.nodeTypes = nodeTypes;
|
||||
},
|
||||
removeNodeTypes(nodeTypesToRemove: INodeTypeDescription[]): void {
|
||||
this.nodeTypes = nodeTypesToRemove.reduce(
|
||||
|
|
|
@ -26,7 +26,6 @@ import type {
|
|||
WorkflowSettings,
|
||||
} from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import { useRootStore } from './n8nRoot.store';
|
||||
import { useUIStore } from './ui.store';
|
||||
import { useUsersStore } from './users.store';
|
||||
|
@ -220,13 +219,19 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
|||
useVersionsStore().setVersionNotificationSettings(settings.versionNotifications);
|
||||
},
|
||||
stopShowingSetupPage(): void {
|
||||
Vue.set(this.userManagement, 'showSetupOnFirstLoad', false);
|
||||
this.userManagement.showSetupOnFirstLoad = false;
|
||||
},
|
||||
disableTemplates(): void {
|
||||
Vue.set(this.settings.templates, 'enabled', false);
|
||||
this.settings = {
|
||||
...this.settings,
|
||||
templates: {
|
||||
...this.settings.templates,
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
setPromptsData(promptsData: IN8nPrompts): void {
|
||||
Vue.set(this, 'promptsData', promptsData);
|
||||
this.promptsData = promptsData;
|
||||
},
|
||||
setAllowedModules(allowedModules: { builtIn?: string[]; external?: string[] }): void {
|
||||
this.settings.allowedModules = allowedModules;
|
||||
|
@ -315,13 +320,13 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
|||
return runLdapSync(rootStore.getRestApiContext, data);
|
||||
},
|
||||
setSaveDataErrorExecution(newValue: string) {
|
||||
Vue.set(this, 'saveDataErrorExecution', newValue);
|
||||
this.saveDataErrorExecution = newValue;
|
||||
},
|
||||
setSaveDataSuccessExecution(newValue: string) {
|
||||
Vue.set(this, 'saveDataSuccessExecution', newValue);
|
||||
this.saveDataSuccessExecution = newValue;
|
||||
},
|
||||
setSaveManualExecutions(saveManualExecutions: boolean) {
|
||||
Vue.set(this, 'saveManualExecutions', saveManualExecutions);
|
||||
this.saveManualExecutions = saveManualExecutions;
|
||||
},
|
||||
async getTimezones(): Promise<IDataObject> {
|
||||
const rootStore = useRootStore();
|
||||
|
|
|
@ -45,9 +45,15 @@ export const useTagsStore = defineStore(STORES.TAGS, {
|
|||
...currentTag,
|
||||
...tag,
|
||||
};
|
||||
Vue.set(this.tags, tagId, newTag);
|
||||
this.tags = {
|
||||
...this.tags,
|
||||
[tagId]: newTag,
|
||||
};
|
||||
} else {
|
||||
Vue.set(this.tags, tagId, tag);
|
||||
this.tags = {
|
||||
...this.tags,
|
||||
[tagId]: tag,
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ import type {
|
|||
ITemplatesWorkflowFull,
|
||||
IWorkflowTemplate,
|
||||
} from '@/Interface';
|
||||
import Vue from 'vue';
|
||||
import { useSettingsStore } from './settings.store';
|
||||
import {
|
||||
getCategories,
|
||||
|
@ -104,27 +103,38 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
actions: {
|
||||
addCategories(categories: ITemplatesCategory[]): void {
|
||||
categories.forEach((category: ITemplatesCategory) => {
|
||||
Vue.set(this.categories, category.id, category);
|
||||
this.categories = {
|
||||
...this.categories,
|
||||
[category.id]: category,
|
||||
};
|
||||
});
|
||||
},
|
||||
addCollections(collections: Array<ITemplatesCollection | ITemplatesCollectionFull>): void {
|
||||
collections.forEach((collection) => {
|
||||
const workflows = (collection.workflows || []).map((workflow) => ({ id: workflow.id }));
|
||||
const cachedCollection = this.collections[collection.id] || {};
|
||||
Vue.set(this.collections, collection.id, {
|
||||
|
||||
this.collections = {
|
||||
...this.collections,
|
||||
[collection.id]: {
|
||||
...cachedCollection,
|
||||
...collection,
|
||||
workflows,
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
addWorkflows(workflows: Array<ITemplatesWorkflow | ITemplatesWorkflowFull>): void {
|
||||
workflows.forEach((workflow: ITemplatesWorkflow) => {
|
||||
const cachedWorkflow = this.workflows[workflow.id] || {};
|
||||
Vue.set(this.workflows, workflow.id, {
|
||||
|
||||
this.workflows = {
|
||||
...this.workflows,
|
||||
[workflow.id]: {
|
||||
...cachedWorkflow,
|
||||
...workflow,
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
addCollectionSearch(data: {
|
||||
|
@ -133,9 +143,13 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
}): void {
|
||||
const collectionIds = data.collections.map((collection) => collection.id);
|
||||
const searchKey = getSearchKey(data.query);
|
||||
Vue.set(this.collectionSearches, searchKey, {
|
||||
|
||||
this.collectionSearches = {
|
||||
...this.collectionSearches,
|
||||
[searchKey]: {
|
||||
collectionIds,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
addWorkflowsSearch(data: {
|
||||
totalWorkflows: number;
|
||||
|
@ -146,18 +160,24 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
const searchKey = getSearchKey(data.query);
|
||||
const cachedResults = this.workflowSearches[searchKey];
|
||||
if (!cachedResults) {
|
||||
Vue.set(this.workflowSearches, searchKey, {
|
||||
workflowIds,
|
||||
this.workflowSearches = {
|
||||
...this.workflowSearches,
|
||||
[searchKey]: {
|
||||
workflowIds: workflowIds as unknown as string[],
|
||||
totalWorkflows: data.totalWorkflows,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vue.set(this.workflowSearches, searchKey, {
|
||||
workflowIds: [...cachedResults.workflowIds, ...workflowIds],
|
||||
this.workflowSearches = {
|
||||
...this.workflowSearches,
|
||||
[searchKey]: {
|
||||
workflowIds: [...cachedResults.workflowIds, ...workflowIds] as string[],
|
||||
totalWorkflows: data.totalWorkflows,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
setWorkflowSearchLoading(query: ITemplatesQuery): void {
|
||||
const searchKey = getSearchKey(query);
|
||||
|
@ -166,7 +186,10 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
return;
|
||||
}
|
||||
|
||||
Vue.set(this.workflowSearches[searchKey], 'loadingMore', true);
|
||||
this.workflowSearches[searchKey] = {
|
||||
...this.workflowSearches[searchKey],
|
||||
loadingMore: true,
|
||||
};
|
||||
},
|
||||
setWorkflowSearchLoaded(query: ITemplatesQuery): void {
|
||||
const searchKey = getSearchKey(query);
|
||||
|
@ -175,7 +198,10 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
|||
return;
|
||||
}
|
||||
|
||||
Vue.set(this.workflowSearches[searchKey], 'loadingMore', false);
|
||||
this.workflowSearches[searchKey] = {
|
||||
...this.workflowSearches[searchKey],
|
||||
loadingMore: false,
|
||||
};
|
||||
},
|
||||
resetSessionId(): void {
|
||||
this.previousSessionId = this.currentSessionId;
|
||||
|
|
|
@ -42,7 +42,6 @@ import type {
|
|||
UIState,
|
||||
XYPosition,
|
||||
} from '@/Interface';
|
||||
import Vue from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useRootStore } from './n8nRoot.store';
|
||||
import { getCurlToJson } from '@/api/curlHelper';
|
||||
|
@ -51,6 +50,7 @@ import { useSettingsStore } from './settings.store';
|
|||
import { useCloudPlanStore } from './cloudPlan.store';
|
||||
import type { BaseTextKey } from '@/plugins/i18n';
|
||||
import { i18n as locale } from '@/plugins/i18n';
|
||||
import type { Modals, NewCredentialsModal } from '@/Interface';
|
||||
import { useTelemetryStore } from '@/stores/telemetry.store';
|
||||
|
||||
export const useUIStore = defineStore(STORES.UI, {
|
||||
|
@ -332,36 +332,57 @@ export const useUIStore = defineStore(STORES.UI, {
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
setMode(name: string, mode: string): void {
|
||||
Vue.set(this.modals[name], 'mode', mode);
|
||||
setMode(name: keyof Modals, mode: string): void {
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
mode,
|
||||
};
|
||||
},
|
||||
setActiveId(name: string, id: string): void {
|
||||
Vue.set(this.modals[name], 'activeId', id);
|
||||
setActiveId(name: keyof Modals, activeId: string): void {
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
activeId,
|
||||
};
|
||||
},
|
||||
setShowAuthSelector(name: string, show: boolean) {
|
||||
Vue.set(this.modals[name], 'showAuthSelector', show);
|
||||
setShowAuthSelector(name: keyof Modals, showAuthSelector: boolean) {
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
showAuthSelector,
|
||||
} as NewCredentialsModal;
|
||||
},
|
||||
setModalData(payload: { name: string; data: Record<string, unknown> }) {
|
||||
Vue.set(this.modals[payload.name], 'data', payload.data);
|
||||
setModalData(payload: { name: keyof Modals; data: Record<string, unknown> }) {
|
||||
this.modals[payload.name] = {
|
||||
...this.modals[payload.name],
|
||||
data: payload.data,
|
||||
};
|
||||
},
|
||||
openModal(name: string): void {
|
||||
Vue.set(this.modals[name], 'open', true);
|
||||
this.modalStack = [name].concat(this.modalStack);
|
||||
openModal(name: keyof Modals): void {
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
open: true,
|
||||
};
|
||||
this.modalStack = [name].concat(this.modalStack) as string[];
|
||||
},
|
||||
openModalWithData(payload: { name: string; data: Record<string, unknown> }): void {
|
||||
openModalWithData(payload: { name: keyof Modals; data: Record<string, unknown> }): void {
|
||||
this.setModalData(payload);
|
||||
this.openModal(payload.name);
|
||||
},
|
||||
closeModal(name: string): void {
|
||||
Vue.set(this.modals[name], 'open', false);
|
||||
closeModal(name: keyof Modals): void {
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
open: false,
|
||||
};
|
||||
this.modalStack = this.modalStack.filter((openModalName: string) => {
|
||||
return name !== openModalName;
|
||||
});
|
||||
},
|
||||
closeAllModals(): void {
|
||||
Object.keys(this.modals).forEach((name: string) => {
|
||||
Object.keys(this.modals).forEach((name) => {
|
||||
if (this.modals[name].open) {
|
||||
Vue.set(this.modals[name], 'open', false);
|
||||
this.modals[name] = {
|
||||
...this.modals[name],
|
||||
open: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
this.modalStack = [];
|
||||
|
@ -385,10 +406,16 @@ export const useUIStore = defineStore(STORES.UI, {
|
|||
};
|
||||
},
|
||||
setDraggableStickyPos(position: XYPosition): void {
|
||||
Vue.set(this.draggable, 'stickyPosition', position);
|
||||
this.draggable = {
|
||||
...this.draggable,
|
||||
stickyPosition: position,
|
||||
};
|
||||
},
|
||||
setDraggableCanDrop(canDrop: boolean): void {
|
||||
Vue.set(this.draggable, 'canDrop', canDrop);
|
||||
this.draggable = {
|
||||
...this.draggable,
|
||||
canDrop,
|
||||
};
|
||||
},
|
||||
openDeleteUserModal(id: string): void {
|
||||
this.setActiveId(DELETE_USER_MODAL_KEY, id);
|
||||
|
@ -460,17 +487,23 @@ export const useUIStore = defineStore(STORES.UI, {
|
|||
}
|
||||
},
|
||||
resetSelectedNodes(): void {
|
||||
Vue.set(this, 'selectedNodes', []);
|
||||
this.selectedNodes = [];
|
||||
},
|
||||
addSidebarMenuItems(menuItems: IMenuItem[]) {
|
||||
const updated = this.sidebarMenuItems.concat(menuItems);
|
||||
Vue.set(this, 'sidebarMenuItems', updated);
|
||||
this.sidebarMenuItems = updated;
|
||||
},
|
||||
setCurlCommand(payload: { name: string; command: string }): void {
|
||||
Vue.set(this.modals[payload.name], 'curlCommand', payload.command);
|
||||
this.modals[payload.name] = {
|
||||
...this.modals[payload.name],
|
||||
curlCommand: payload.command,
|
||||
};
|
||||
},
|
||||
setHttpNodeParameters(payload: { name: string; parameters: string }): void {
|
||||
Vue.set(this.modals[payload.name], 'httpNodeParameters', payload.parameters);
|
||||
this.modals[payload.name] = {
|
||||
...this.modals[payload.name],
|
||||
httpNodeParameters: payload.parameters,
|
||||
};
|
||||
},
|
||||
toggleSidebarMenuCollapse(): void {
|
||||
this.sidebarMenuCollapsed = !this.sidebarMenuCollapsed;
|
||||
|
|
|
@ -35,7 +35,6 @@ import type {
|
|||
import { getCredentialPermissions } from '@/permissions';
|
||||
import { getPersonalizedNodeTypes, isAuthorized, PERMISSIONS, ROLE } from '@/utils';
|
||||
import { defineStore } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import { useRootStore } from './n8nRoot.store';
|
||||
import { usePostHog } from './posthog.store';
|
||||
import { useSettingsStore } from './settings.store';
|
||||
|
@ -133,17 +132,29 @@ export const useUsersStore = defineStore(STORES.USERS, {
|
|||
isPendingUser: isPendingUser(updatedUser),
|
||||
isOwner: updatedUser.globalRole?.name === ROLE.Owner,
|
||||
};
|
||||
Vue.set(this.users, user.id, user);
|
||||
|
||||
this.users = {
|
||||
...this.users,
|
||||
[user.id]: user,
|
||||
};
|
||||
});
|
||||
},
|
||||
deleteUserById(userId: string): void {
|
||||
Vue.delete(this.users, userId);
|
||||
const { [userId]: _, ...users } = this.users;
|
||||
this.users = users;
|
||||
},
|
||||
setPersonalizationAnswers(answers: IPersonalizationLatestVersion): void {
|
||||
if (!this.currentUser) {
|
||||
return;
|
||||
}
|
||||
Vue.set(this.currentUser, 'personalizationAnswers', answers);
|
||||
|
||||
this.users = {
|
||||
...this.users,
|
||||
[this.currentUser.id]: {
|
||||
...this.currentUser,
|
||||
personalizationAnswers: answers,
|
||||
},
|
||||
};
|
||||
},
|
||||
async loginWithCookie(): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import Vue from 'vue';
|
||||
import type { IUser } from '../Interface';
|
||||
import { setWorkflowSharedWith } from '@/api/workflows.ee';
|
||||
import { EnterpriseEditionFeature, STORES } from '@/constants';
|
||||
|
@ -29,8 +28,14 @@ export const useWorkflowsEEStore = defineStore(STORES.WORKFLOWS_EE, {
|
|||
setWorkflowOwnedBy(payload: { workflowId: string; ownedBy: Partial<IUser> }): void {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
Vue.set(workflowsStore.workflowsById[payload.workflowId], 'ownedBy', payload.ownedBy);
|
||||
Vue.set(workflowsStore.workflow, 'ownedBy', payload.ownedBy);
|
||||
workflowsStore.workflowsById[payload.workflowId] = {
|
||||
...workflowsStore.workflowsById[payload.workflowId],
|
||||
ownedBy: payload.ownedBy,
|
||||
};
|
||||
workflowsStore.workflow = {
|
||||
...workflowsStore.workflow,
|
||||
ownedBy: payload.ownedBy,
|
||||
};
|
||||
},
|
||||
setWorkflowSharedWith(payload: {
|
||||
workflowId: string;
|
||||
|
@ -38,30 +43,34 @@ export const useWorkflowsEEStore = defineStore(STORES.WORKFLOWS_EE, {
|
|||
}): void {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
Vue.set(workflowsStore.workflowsById[payload.workflowId], 'sharedWith', payload.sharedWith);
|
||||
Vue.set(workflowsStore.workflow, 'sharedWith', payload.sharedWith);
|
||||
workflowsStore.workflowsById[payload.workflowId] = {
|
||||
...workflowsStore.workflowsById[payload.workflowId],
|
||||
sharedWith: payload.sharedWith,
|
||||
};
|
||||
workflowsStore.workflow = {
|
||||
...workflowsStore.workflow,
|
||||
sharedWith: payload.sharedWith,
|
||||
};
|
||||
},
|
||||
addWorkflowSharee(payload: { workflowId: string; sharee: Partial<IUser> }): void {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
Vue.set(
|
||||
workflowsStore.workflowsById[payload.workflowId],
|
||||
'sharedWith',
|
||||
(workflowsStore.workflowsById[payload.workflowId].sharedWith || []).concat([
|
||||
workflowsStore.workflowsById[payload.workflowId] = {
|
||||
...workflowsStore.workflowsById[payload.workflowId],
|
||||
sharedWith: (workflowsStore.workflowsById[payload.workflowId].sharedWith || []).concat([
|
||||
payload.sharee,
|
||||
]),
|
||||
);
|
||||
};
|
||||
},
|
||||
removeWorkflowSharee(payload: { workflowId: string; sharee: Partial<IUser> }): void {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
Vue.set(
|
||||
workflowsStore.workflowsById[payload.workflowId],
|
||||
'sharedWith',
|
||||
(workflowsStore.workflowsById[payload.workflowId].sharedWith || []).filter(
|
||||
workflowsStore.workflowsById[payload.workflowId] = {
|
||||
...workflowsStore.workflowsById[payload.workflowId],
|
||||
sharedWith: (workflowsStore.workflowsById[payload.workflowId].sharedWith || []).filter(
|
||||
(sharee) => sharee.id !== payload.sharee.id,
|
||||
),
|
||||
);
|
||||
};
|
||||
},
|
||||
async saveWorkflowSharedWith(payload: {
|
||||
sharedWith: Array<Partial<IUser>>;
|
||||
|
|
|
@ -18,6 +18,7 @@ import type {
|
|||
IExecutionsListResponse,
|
||||
IExecutionsStopData,
|
||||
INewWorkflowData,
|
||||
INodeMetadata,
|
||||
INodeUi,
|
||||
INodeUpdatePropertiesInformation,
|
||||
IPushDataExecutionFinished,
|
||||
|
@ -26,6 +27,7 @@ import type {
|
|||
IStartRunData,
|
||||
IUpdateInformation,
|
||||
IUsedCredential,
|
||||
IUser,
|
||||
IWorkflowDataUpdate,
|
||||
IWorkflowDb,
|
||||
IWorkflowsMap,
|
||||
|
@ -44,6 +46,7 @@ import type {
|
|||
INodeCredentialsDetails,
|
||||
INodeExecutionData,
|
||||
INodeIssueData,
|
||||
INodeIssueObjectProperty,
|
||||
INodeParameters,
|
||||
INodeTypeData,
|
||||
INodeTypes,
|
||||
|
@ -83,6 +86,7 @@ import { useNodeTypesStore } from './nodeTypes.store';
|
|||
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import type { NodeMetadataMap } from '@/Interface';
|
||||
|
||||
const createEmptyWorkflow = (): IWorkflowDb => ({
|
||||
id: PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
||||
|
@ -416,7 +420,10 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
this.workflow = createEmptyWorkflow();
|
||||
|
||||
if (settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing)) {
|
||||
Vue.set(this.workflow, 'ownedBy', usersStore.currentUser);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
ownedBy: usersStore.currentUser as IUser,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -509,10 +516,13 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
},
|
||||
|
||||
addWorkflow(workflow: IWorkflowDb): void {
|
||||
Vue.set(this.workflowsById, workflow.id, {
|
||||
this.workflowsById = {
|
||||
...this.workflowsById,
|
||||
[workflow.id]: {
|
||||
...this.workflowsById[workflow.id],
|
||||
...deepCopy(workflow),
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
setWorkflowActive(workflowId: string): void {
|
||||
|
@ -576,57 +586,60 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
},
|
||||
|
||||
setWorkflowSettings(workflowSettings: IWorkflowSettings): void {
|
||||
Vue.set(this.workflow, 'settings', workflowSettings);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
settings: workflowSettings as IWorkflowDb['settings'],
|
||||
};
|
||||
},
|
||||
|
||||
setWorkflowPinData(pinData: IPinData): void {
|
||||
Vue.set(this.workflow, 'pinData', pinData || {});
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
pinData: pinData || {},
|
||||
};
|
||||
dataPinningEventBus.emit('pin-data', pinData || {});
|
||||
},
|
||||
|
||||
setWorkflowTagIds(tags: string[]): void {
|
||||
Vue.set(this.workflow, 'tags', tags);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
tags,
|
||||
};
|
||||
},
|
||||
|
||||
addWorkflowTagIds(tags: string[]): void {
|
||||
Vue.set(this.workflow, 'tags', [...new Set([...(this.workflow.tags || []), ...tags])]);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
tags: [...new Set([...(this.workflow.tags || []), ...tags])] as IWorkflowDb['tags'],
|
||||
};
|
||||
},
|
||||
|
||||
removeWorkflowTagId(tagId: string): void {
|
||||
const tags = this.workflow.tags as string[];
|
||||
const updated = tags.filter((id: string) => id !== tagId);
|
||||
Vue.set(this.workflow, 'tags', updated);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
tags: updated as IWorkflowDb['tags'],
|
||||
};
|
||||
},
|
||||
|
||||
setWorkflow(workflow: IWorkflowDb): void {
|
||||
Vue.set(this, 'workflow', workflow);
|
||||
|
||||
if (!this.workflow.hasOwnProperty('active')) {
|
||||
Vue.set(this.workflow, 'active', false);
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('connections')) {
|
||||
Vue.set(this.workflow, 'connections', {});
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('createdAt')) {
|
||||
Vue.set(this.workflow, 'createdAt', -1);
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('updatedAt')) {
|
||||
Vue.set(this.workflow, 'updatedAt', -1);
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('id')) {
|
||||
Vue.set(this.workflow, 'id', PLACEHOLDER_EMPTY_WORKFLOW_ID);
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('nodes')) {
|
||||
Vue.set(this.workflow, 'nodes', []);
|
||||
}
|
||||
if (!this.workflow.hasOwnProperty('settings')) {
|
||||
Vue.set(this.workflow, 'settings', {});
|
||||
}
|
||||
this.workflow = workflow;
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
...(!this.workflow.hasOwnProperty('active') ? { active: false } : {}),
|
||||
...(!this.workflow.hasOwnProperty('connections') ? { connections: {} } : {}),
|
||||
...(!this.workflow.hasOwnProperty('createdAt') ? { createdAt: -1 } : {}),
|
||||
...(!this.workflow.hasOwnProperty('updatedAt') ? { updatedAt: -1 } : {}),
|
||||
...(!this.workflow.hasOwnProperty('id') ? { id: PLACEHOLDER_EMPTY_WORKFLOW_ID } : {}),
|
||||
...(!this.workflow.hasOwnProperty('nodes') ? { nodes: [] } : {}),
|
||||
...(!this.workflow.hasOwnProperty('settings') ? { settings: {} } : {}),
|
||||
};
|
||||
},
|
||||
|
||||
pinData(payload: { node: INodeUi; data: INodeExecutionData[] }): void {
|
||||
if (!this.workflow.pinData) {
|
||||
Vue.set(this.workflow, 'pinData', {});
|
||||
this.workflow = { ...this.workflow, pinData: {} };
|
||||
}
|
||||
|
||||
if (!Array.isArray(payload.data)) {
|
||||
|
@ -637,7 +650,13 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
isJsonKeyObject(item) ? item : { json: item },
|
||||
);
|
||||
|
||||
Vue.set(this.workflow.pinData!, payload.node.name, storedPinData);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
pinData: {
|
||||
...this.workflow.pinData,
|
||||
[payload.node.name]: storedPinData,
|
||||
},
|
||||
};
|
||||
|
||||
const uiStore = useUIStore();
|
||||
uiStore.stateIsDirty = true;
|
||||
|
@ -647,11 +666,14 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
|
||||
unpinData(payload: { node: INodeUi }): void {
|
||||
if (!this.workflow.pinData) {
|
||||
Vue.set(this.workflow, 'pinData', {});
|
||||
this.workflow = { ...this.workflow, pinData: {} };
|
||||
}
|
||||
|
||||
Vue.set(this.workflow.pinData!, payload.node.name, undefined);
|
||||
delete this.workflow.pinData![payload.node.name];
|
||||
const { [payload.node.name]: _, ...pinData } = this.workflow.pinData!;
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
pinData,
|
||||
};
|
||||
|
||||
const uiStore = useUIStore();
|
||||
uiStore.stateIsDirty = true;
|
||||
|
@ -670,10 +692,25 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
|
||||
// Check if source node and type exist already and if not add them
|
||||
if (!this.workflow.connections.hasOwnProperty(sourceData.node)) {
|
||||
Vue.set(this.workflow.connections, sourceData.node, {});
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
connections: {
|
||||
...this.workflow.connections,
|
||||
[sourceData.node]: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!this.workflow.connections[sourceData.node].hasOwnProperty(sourceData.type)) {
|
||||
Vue.set(this.workflow.connections[sourceData.node], sourceData.type, []);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
connections: {
|
||||
...this.workflow.connections,
|
||||
[sourceData.node]: {
|
||||
...this.workflow.connections[sourceData.node],
|
||||
[sourceData.type]: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
this.workflow.connections[sourceData.node][sourceData.type].length <
|
||||
|
@ -817,12 +854,19 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
uiStore.lastSelectedNode = nameData.new;
|
||||
}
|
||||
|
||||
Vue.set(this.nodeMetadata, nameData.new, this.nodeMetadata[nameData.old]);
|
||||
this.nodeMetadata = { ...this.nodeMetadata, [nameData.new]: this.nodeMetadata[nameData.old] };
|
||||
Vue.delete(this.nodeMetadata, nameData.old);
|
||||
|
||||
if (this.workflow.pinData && this.workflow.pinData.hasOwnProperty(nameData.old)) {
|
||||
Vue.set(this.workflow.pinData, nameData.new, this.workflow.pinData[nameData.old]);
|
||||
Vue.delete(this.workflow.pinData, nameData.old);
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
pinData: {
|
||||
...this.workflow.pinData,
|
||||
[nameData.new]: this.workflow.pinData[nameData.old],
|
||||
},
|
||||
};
|
||||
|
||||
Vue.delete(this.workflow.pinData!, nameData.old);
|
||||
}
|
||||
|
||||
this.workflowExecutionPairedItemMappings = getPairedItemsMapping(this.workflowExecutionData);
|
||||
|
@ -835,13 +879,31 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
return true;
|
||||
},
|
||||
|
||||
updateNodeAtIndex(nodeIndex: number, nodeData: Partial<INodeUi>): void {
|
||||
if (nodeIndex !== -1) {
|
||||
const node = this.workflow.nodes[nodeIndex];
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
nodes: [
|
||||
...this.workflow.nodes.slice(0, nodeIndex),
|
||||
{ ...node, ...nodeData },
|
||||
...this.workflow.nodes.slice(nodeIndex + 1),
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
setNodeIssue(nodeIssueData: INodeIssueData): boolean {
|
||||
const node = this.workflow.nodes.find((node) => {
|
||||
const nodeIndex = this.workflow.nodes.findIndex((node) => {
|
||||
return node.name === nodeIssueData.node;
|
||||
});
|
||||
if (!node) {
|
||||
|
||||
if (nodeIndex === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const node = this.workflow.nodes[nodeIndex!];
|
||||
|
||||
if (nodeIssueData.value === null) {
|
||||
// Remove the value if one exists
|
||||
if (node.issues === undefined || node.issues[nodeIssueData.type] === undefined) {
|
||||
|
@ -853,10 +915,17 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
Vue.delete(node.issues, nodeIssueData.type);
|
||||
} else {
|
||||
if (node.issues === undefined) {
|
||||
Vue.set(node, 'issues', {});
|
||||
this.updateNodeAtIndex(nodeIndex, {
|
||||
issues: {},
|
||||
});
|
||||
}
|
||||
// Set/Overwrite the value
|
||||
Vue.set(node.issues!, nodeIssueData.type, nodeIssueData.value);
|
||||
|
||||
this.updateNodeAtIndex(nodeIndex, {
|
||||
issues: {
|
||||
...node.issues,
|
||||
[nodeIssueData.type]: nodeIssueData.value as INodeIssueObjectProperty,
|
||||
},
|
||||
});
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
@ -871,7 +940,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
this.workflow.nodes.push(nodeData);
|
||||
// Init node metadata
|
||||
if (!this.nodeMetadata[nodeData.name]) {
|
||||
Vue.set(this.nodeMetadata, nodeData.name, {});
|
||||
this.nodeMetadata = { ...this.nodeMetadata, [nodeData.name]: {} as INodeMetadata };
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -899,7 +968,10 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
}
|
||||
|
||||
if (data.removePinData) {
|
||||
Vue.set(this.workflow, 'pinData', {});
|
||||
this.workflow = {
|
||||
...this.workflow,
|
||||
pinData: {},
|
||||
};
|
||||
}
|
||||
|
||||
this.workflow.nodes.splice(0, this.workflow.nodes.length);
|
||||
|
@ -908,26 +980,29 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
|
||||
updateNodeProperties(updateInformation: INodeUpdatePropertiesInformation): void {
|
||||
// Find the node that should be updated
|
||||
const node = this.workflow.nodes.find((node) => {
|
||||
const nodeIndex = this.workflow.nodes.findIndex((node) => {
|
||||
return node.name === updateInformation.name;
|
||||
});
|
||||
|
||||
if (node) {
|
||||
if (nodeIndex !== -1) {
|
||||
for (const key of Object.keys(updateInformation.properties)) {
|
||||
const uiStore = useUIStore();
|
||||
uiStore.stateIsDirty = true;
|
||||
Vue.set(node, key, updateInformation.properties[key]);
|
||||
|
||||
this.updateNodeAtIndex(nodeIndex, {
|
||||
[key]: updateInformation.properties[key],
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setNodeValue(updateInformation: IUpdateInformation): void {
|
||||
// Find the node that should be updated
|
||||
const node = this.workflow.nodes.find((node) => {
|
||||
const nodeIndex = this.workflow.nodes.findIndex((node) => {
|
||||
return node.name === updateInformation.name;
|
||||
});
|
||||
|
||||
if (node === undefined || node === null || !updateInformation.key) {
|
||||
if (nodeIndex === -1 || !updateInformation.key) {
|
||||
throw new Error(
|
||||
`Node with the name "${updateInformation.name}" could not be found to set parameter.`,
|
||||
);
|
||||
|
@ -935,21 +1010,26 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
|
||||
const uiStore = useUIStore();
|
||||
uiStore.stateIsDirty = true;
|
||||
Vue.set(node, updateInformation.key, updateInformation.value);
|
||||
|
||||
this.updateNodeAtIndex(nodeIndex, {
|
||||
[updateInformation.key]: updateInformation.value,
|
||||
});
|
||||
},
|
||||
|
||||
setNodeParameters(updateInformation: IUpdateInformation, append?: boolean): void {
|
||||
// Find the node that should be updated
|
||||
const node = this.workflow.nodes.find((node) => {
|
||||
const nodeIndex = this.workflow.nodes.findIndex((node) => {
|
||||
return node.name === updateInformation.name;
|
||||
});
|
||||
|
||||
if (node === undefined || node === null) {
|
||||
if (nodeIndex === -1) {
|
||||
throw new Error(
|
||||
`Node with the name "${updateInformation.name}" could not be found to set parameter.`,
|
||||
);
|
||||
}
|
||||
|
||||
const node = this.workflow.nodes[nodeIndex];
|
||||
|
||||
const uiStore = useUIStore();
|
||||
uiStore.stateIsDirty = true;
|
||||
const newParameters =
|
||||
|
@ -957,13 +1037,17 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
? { ...node.parameters, ...updateInformation.value }
|
||||
: updateInformation.value;
|
||||
|
||||
Vue.set(node, 'parameters', newParameters);
|
||||
this.updateNodeAtIndex(nodeIndex, {
|
||||
parameters: newParameters as INodeParameters,
|
||||
});
|
||||
|
||||
if (!this.nodeMetadata[node.name]) {
|
||||
Vue.set(this.nodeMetadata, node.name, {});
|
||||
}
|
||||
|
||||
Vue.set(this.nodeMetadata[node.name], 'parametersLastUpdatedAt', Date.now());
|
||||
this.nodeMetadata = {
|
||||
...this.nodeMetadata,
|
||||
[node.name]: {
|
||||
...this.nodeMetadata[node.name],
|
||||
parametersLastUpdatedAt: Date.now(),
|
||||
},
|
||||
} as NodeMetadataMap;
|
||||
},
|
||||
|
||||
setLastNodeParameters(updateInformation: IUpdateInformation) {
|
||||
|
@ -989,9 +1073,21 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
throw new Error('The "workflowExecutionData" is not initialized!');
|
||||
}
|
||||
if (this.workflowExecutionData.data.resultData.runData[pushData.nodeName] === undefined) {
|
||||
Vue.set(this.workflowExecutionData.data.resultData.runData, pushData.nodeName, []);
|
||||
this.workflowExecutionData = {
|
||||
...this.workflowExecutionData,
|
||||
data: {
|
||||
...this.workflowExecutionData.data,
|
||||
resultData: {
|
||||
...this.workflowExecutionData.data.resultData,
|
||||
runData: {
|
||||
...this.workflowExecutionData.data.resultData.runData,
|
||||
[pushData.nodeName]: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
this.workflowExecutionData.data.resultData.runData[pushData.nodeName].push(pushData.data);
|
||||
this.workflowExecutionData.data!.resultData.runData[pushData.nodeName].push(pushData.data);
|
||||
this.workflowExecutionPairedItemMappings = getPairedItemsMapping(this.workflowExecutionData);
|
||||
},
|
||||
clearNodeExecutionData(nodeName: string): void {
|
||||
|
@ -1033,28 +1129,37 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
finishedActiveExecution: IPushDataExecutionFinished | IPushDataUnsavedExecutionFinished,
|
||||
): void {
|
||||
// Find the execution to set to finished
|
||||
const activeExecution = this.activeExecutions.find((execution) => {
|
||||
const activeExecutionIndex = this.activeExecutions.findIndex((execution) => {
|
||||
return execution.id === finishedActiveExecution.executionId;
|
||||
});
|
||||
|
||||
if (activeExecution === undefined) {
|
||||
if (activeExecutionIndex === -1) {
|
||||
// The execution could not be found
|
||||
return;
|
||||
}
|
||||
|
||||
if (finishedActiveExecution.executionId !== undefined) {
|
||||
Vue.set(activeExecution, 'id', finishedActiveExecution.executionId);
|
||||
}
|
||||
const activeExecution = this.activeExecutions[activeExecutionIndex];
|
||||
|
||||
this.activeExecutions = [
|
||||
...this.activeExecutions.slice(0, activeExecutionIndex),
|
||||
{
|
||||
...activeExecution,
|
||||
...(finishedActiveExecution.executionId !== undefined
|
||||
? { id: finishedActiveExecution.executionId }
|
||||
: {}),
|
||||
finished: finishedActiveExecution.data.finished,
|
||||
stoppedAt: finishedActiveExecution.data.stoppedAt,
|
||||
},
|
||||
...this.activeExecutions.slice(activeExecutionIndex + 1),
|
||||
];
|
||||
|
||||
Vue.set(activeExecution, 'finished', finishedActiveExecution.data.finished);
|
||||
Vue.set(activeExecution, 'stoppedAt', finishedActiveExecution.data.stoppedAt);
|
||||
if (finishedActiveExecution.data && (finishedActiveExecution.data as IRun).data) {
|
||||
this.setWorkflowExecutionRunData((finishedActiveExecution.data as IRun).data);
|
||||
}
|
||||
},
|
||||
|
||||
setActiveExecutions(newActiveExecutions: IExecutionsCurrentSummaryExtended[]): void {
|
||||
Vue.set(this, 'activeExecutions', newActiveExecutions);
|
||||
this.activeExecutions = newActiveExecutions;
|
||||
},
|
||||
|
||||
async retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean> {
|
||||
|
@ -1247,7 +1352,13 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
|
|||
},
|
||||
|
||||
setNodePristine(nodeName: string, isPristine: boolean): void {
|
||||
Vue.set(this.nodeMetadata[nodeName], 'pristine', isPristine);
|
||||
this.nodeMetadata = {
|
||||
...this.nodeMetadata,
|
||||
[nodeName]: {
|
||||
...this.nodeMetadata[nodeName],
|
||||
pristine: isPristine,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue