Files
Automata/packages/editor-ui/src/components/WorkflowOpen.vue
Ahsan Virani 421dd72224 Introduce telemetry (#2099)
* introduce analytics

* add user survey backend

* add user survey backend

* set answers on survey submit

Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>

* change name to personalization

* lint

Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>

* N8n 2495 add personalization modal (#2280)

* update modals

* add onboarding modal

* implement questions

* introduce analytics

* simplify impl

* implement survey handling

* add personalized cateogry

* update modal behavior

* add thank you view

* handle empty cases

* rename modal

* standarize modal names

* update image, add tags to headings

* remove unused file

* remove unused interfaces

* clean up footer spacing

* introduce analytics

* refactor to fix bug

* update endpoint

* set min height

* update stories

* update naming from questions to survey

* remove spacing after core categories

* fix bug in logic

* sort nodes

* rename types

* merge with be

* rename userSurvey

* clean up rest api

* use constants for keys

* use survey keys

* clean up types

* move personalization to its own file

Co-authored-by: ahsan-virani <ahsan.virani@gmail.com>

* Survey new options (#2300)

* split up options

* fix quotes

* remove unused import

* add user created workflow event (#2301)

* simplify env vars

* fix versionCli on FE

* update personalization env

* fix event User opened Credentials panel

* fix select modal spacing

* fix nodes panel event

* fix workflow id in workflow execute event

* improve telemetry error logging

* fix config and stop process events

* add flush call on n8n stop

* ready for release

* improve telemetry process exit

* fix merge

* improve n8n stop events

Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-10-19 05:57:49 +02:00

240 lines
6.7 KiB
Vue

<template>
<Modal
:name="WORKFLOW_OPEN_MODAL_KEY"
width="80%"
minWidth="620px"
:classic="true"
>
<template v-slot:header>
<div class="workflows-header">
<n8n-heading tag="h1" size="xlarge" class="title">
Open Workflow
</n8n-heading>
<div class="tags-filter">
<TagsDropdown
placeholder="Filter by tags..."
:currentTagIds="filterTagIds"
:createEnabled="false"
@update="updateTagsFilter"
@esc="onTagsFilterEsc"
@blur="onTagsFilterBlur"
/>
</div>
<div class="search-filter">
<n8n-input placeholder="Search workflows..." ref="inputFieldFilter" v-model="filterText">
<font-awesome-icon slot="prefix" icon="search"></font-awesome-icon>
</n8n-input>
</div>
</div>
</template>
<template v-slot:content>
<el-table class="search-table" :data="filteredWorkflows" stripe @cell-click="openWorkflow" :default-sort = "{prop: 'updatedAt', order: 'descending'}" v-loading="isDataLoading">
<el-table-column property="name" label="Name" class-name="clickable" sortable>
<template slot-scope="scope">
<div :key="scope.row.id">
<span class="name">{{scope.row.name}}</span>
<TagsContainer class="hidden-sm-and-down" :tagIds="getIds(scope.row.tags)" :limit="3" @click="onTagClick" :clickable="true" :hoverable="true" />
</div>
</template>
</el-table-column>
<el-table-column property="createdAt" label="Created" class-name="clickable" width="155" sortable></el-table-column>
<el-table-column property="updatedAt" label="Updated" class-name="clickable" width="155" sortable></el-table-column>
<el-table-column label="Active" width="75">
<template slot-scope="scope">
<workflow-activator :workflow-active="scope.row.active" :workflow-id="scope.row.id" @workflowActiveChanged="workflowActiveChanged" />
</template>
</el-table-column>
</el-table>
</template>
</Modal>
</template>
<script lang="ts">
import Vue from 'vue';
import mixins from 'vue-typed-mixins';
import { ITag, IWorkflowShortResponse } from '@/Interface';
import { restApi } from '@/components/mixins/restApi';
import { genericHelpers } from '@/components/mixins/genericHelpers';
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import Modal from '@/components/Modal.vue';
import TagsContainer from '@/components/TagsContainer.vue';
import TagsDropdown from '@/components/TagsDropdown.vue';
import WorkflowActivator from '@/components/WorkflowActivator.vue';
import { convertToDisplayDate } from './helpers';
import { WORKFLOW_OPEN_MODAL_KEY } from '../constants';
export default mixins(
genericHelpers,
restApi,
showMessage,
workflowHelpers,
).extend({
name: 'WorkflowOpen',
components: {
WorkflowActivator,
TagsContainer,
TagsDropdown,
Modal,
},
props: ['modalName'],
data () {
return {
filterText: '',
isDataLoading: false,
workflows: [] as IWorkflowShortResponse[],
filterTagIds: [] as string[],
prevFilterTagIds: [] as string[],
WORKFLOW_OPEN_MODAL_KEY,
};
},
computed: {
filteredWorkflows (): IWorkflowShortResponse[] {
return this.workflows
.filter((workflow: IWorkflowShortResponse) => {
if (this.filterText && !workflow.name.toLowerCase().includes(this.filterText.toLowerCase())) {
return false;
}
if (this.filterTagIds.length === 0) {
return true;
}
if (!workflow.tags || workflow.tags.length === 0) {
return false;
}
return this.filterTagIds.reduce((accu: boolean, id: string) => accu && !!workflow.tags.find(tag => tag.id === id), true);
});
},
},
mounted() {
this.filterText = '';
this.filterTagIds = [];
this.openDialog();
Vue.nextTick(() => {
// Make sure that users can directly type in the filter
(this.$refs.inputFieldFilter as HTMLInputElement).focus();
});
},
methods: {
getIds(tags: ITag[] | undefined) {
return (tags || []).map((tag) => tag.id);
},
updateTagsFilter(tags: string[]) {
this.filterTagIds = tags;
},
onTagClick(tagId: string) {
if (tagId !== 'count' && !this.filterTagIds.includes(tagId)) {
this.filterTagIds.push(tagId);
}
},
async openWorkflow (data: IWorkflowShortResponse, column: any) { // tslint:disable-line:no-any
if (column.label !== 'Active') {
const currentWorkflowId = this.$store.getters.workflowId;
if (data.id === currentWorkflowId) {
this.$showMessage({
title: 'Already open',
message: 'This is the current workflow',
type: 'error',
duration: 1500,
});
// Do nothing if current workflow is the one user chose to open
return;
}
const result = this.$store.getters.getStateIsDirty;
if(result) {
const importConfirm = await this.confirmMessage(`When you switch workflows your current workflow changes will be lost.`, 'Save your Changes?', 'warning', 'Yes, switch workflows and forget changes');
if (importConfirm === false) {
return;
} else {
// This is used to avoid duplicating the message
this.$store.commit('setStateDirty', false);
this.$router.push({
name: 'NodeViewExisting',
params: { name: data.id },
});
}
} else {
this.$router.push({
name: 'NodeViewExisting',
params: { name: data.id },
});
}
this.$store.commit('ui/closeTopModal');
}
},
openDialog () {
this.isDataLoading = true;
this.restApi().getWorkflows()
.then(
(data) => {
this.workflows = data;
this.workflows.forEach((workflowData: IWorkflowShortResponse) => {
workflowData.createdAt = convertToDisplayDate(workflowData.createdAt as number);
workflowData.updatedAt = convertToDisplayDate(workflowData.updatedAt as number);
});
this.isDataLoading = false;
},
)
.catch(
(error: Error) => {
this.$showError(error, 'Problem loading workflows', 'There was a problem loading the workflows:');
this.isDataLoading = false;
},
);
},
workflowActiveChanged (data: { id: string, active: boolean }) {
for (const workflow of this.workflows) {
if (workflow.id === data.id) {
workflow.active = data.active;
}
}
},
onTagsFilterBlur() {
this.prevFilterTagIds = this.filterTagIds;
},
onTagsFilterEsc() {
// revert last applied tags
this.filterTagIds = this.prevFilterTagIds;
},
},
});
</script>
<style scoped lang="scss">
.workflows-header {
display: flex;
> *:first-child {
flex-grow: 1;
}
.search-filter {
margin-left: 10px;
min-width: 160px;
}
.tags-filter {
flex-grow: 1;
max-width: 270px;
min-width: 220px;
}
}
.search-table .name {
font-weight: 400;
margin-right: 10px;
}
</style>