mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 03:42:16 +00:00
* 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>
292 lines
6.5 KiB
Vue
292 lines
6.5 KiB
Vue
<template>
|
|
<div class="container" v-if="workflowName">
|
|
<BreakpointsObserver :valueXS="15" :valueSM="25" :valueMD="50" class="name-container">
|
|
<template v-slot="{ value }">
|
|
<WorkflowNameShort
|
|
:name="workflowName"
|
|
:limit="value"
|
|
:custom="true"
|
|
>
|
|
<template v-slot="{ shortenedName }">
|
|
<InlineTextEdit
|
|
:value="workflowName"
|
|
:previewValue="shortenedName"
|
|
:isEditEnabled="isNameEditEnabled"
|
|
:maxLength="MAX_WORKFLOW_NAME_LENGTH"
|
|
@toggle="onNameToggle"
|
|
@submit="onNameSubmit"
|
|
placeholder="Enter workflow name"
|
|
class="name"
|
|
/>
|
|
</template>
|
|
</WorkflowNameShort>
|
|
</template>
|
|
</BreakpointsObserver>
|
|
|
|
<div
|
|
v-if="isTagsEditEnabled"
|
|
class="tags">
|
|
<TagsDropdown
|
|
:createEnabled="true"
|
|
:currentTagIds="appliedTagIds"
|
|
:eventBus="tagsEditBus"
|
|
@blur="onTagsBlur"
|
|
@update="onTagsUpdate"
|
|
@esc="onTagsEditEsc"
|
|
placeholder="Choose or create a tag"
|
|
ref="dropdown"
|
|
class="tags-edit"
|
|
/>
|
|
</div>
|
|
<div
|
|
class="tags"
|
|
v-else-if="currentWorkflowTagIds.length === 0"
|
|
>
|
|
<span
|
|
class="add-tag clickable"
|
|
@click="onTagsEditEnable"
|
|
>
|
|
+ Add tag
|
|
</span>
|
|
</div>
|
|
<TagsContainer
|
|
v-else
|
|
:tagIds="currentWorkflowTagIds"
|
|
:clickable="true"
|
|
:responsive="true"
|
|
:key="currentWorkflowId"
|
|
@click="onTagsEditEnable"
|
|
class="tags"
|
|
/>
|
|
|
|
<PushConnectionTracker class="actions">
|
|
<template>
|
|
<span class="activator">
|
|
<span>Active:</span>
|
|
<WorkflowActivator :workflow-active="isWorkflowActive" :workflow-id="currentWorkflowId" :disabled="!currentWorkflowId"/>
|
|
</span>
|
|
<SaveButton
|
|
:saved="!this.isDirty && !this.isNewWorkflow"
|
|
:disabled="isWorkflowSaving"
|
|
@click="onSaveButtonClick"
|
|
/>
|
|
</template>
|
|
</PushConnectionTracker>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from "vue";
|
|
import mixins from "vue-typed-mixins";
|
|
import { mapGetters } from "vuex";
|
|
import { MAX_WORKFLOW_NAME_LENGTH } from "@/constants";
|
|
|
|
import WorkflowNameShort from "@/components/WorkflowNameShort.vue";
|
|
import TagsContainer from "@/components/TagsContainer.vue";
|
|
import PushConnectionTracker from "@/components/PushConnectionTracker.vue";
|
|
import WorkflowActivator from "@/components/WorkflowActivator.vue";
|
|
import { workflowHelpers } from "@/components/mixins/workflowHelpers";
|
|
import SaveButton from "@/components/SaveButton.vue";
|
|
import TagsDropdown from "@/components/TagsDropdown.vue";
|
|
import InlineTextEdit from "@/components/InlineTextEdit.vue";
|
|
import BreakpointsObserver from "@/components/BreakpointsObserver.vue";
|
|
|
|
const hasChanged = (prev: string[], curr: string[]) => {
|
|
if (prev.length !== curr.length) {
|
|
return true;
|
|
}
|
|
|
|
const set = new Set(prev);
|
|
return curr.reduce((accu, val) => accu || !set.has(val), false);
|
|
};
|
|
|
|
export default mixins(workflowHelpers).extend({
|
|
name: "WorkflowDetails",
|
|
components: {
|
|
TagsContainer,
|
|
PushConnectionTracker,
|
|
WorkflowNameShort,
|
|
WorkflowActivator,
|
|
SaveButton,
|
|
TagsDropdown,
|
|
InlineTextEdit,
|
|
BreakpointsObserver,
|
|
},
|
|
data() {
|
|
return {
|
|
isTagsEditEnabled: false,
|
|
isNameEditEnabled: false,
|
|
appliedTagIds: [],
|
|
tagsEditBus: new Vue(),
|
|
MAX_WORKFLOW_NAME_LENGTH,
|
|
tagsSaving: false,
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
isWorkflowActive: "isActive",
|
|
workflowName: "workflowName",
|
|
isDirty: "getStateIsDirty",
|
|
currentWorkflowTagIds: "workflowTags",
|
|
}),
|
|
isNewWorkflow(): boolean {
|
|
return !this.$route.params.name;
|
|
},
|
|
isWorkflowSaving(): boolean {
|
|
return this.$store.getters.isActionActive("workflowSaving");
|
|
},
|
|
currentWorkflowId(): string {
|
|
return this.$route.params.name;
|
|
},
|
|
},
|
|
methods: {
|
|
onSaveButtonClick () {
|
|
this.saveCurrentWorkflow(undefined);
|
|
},
|
|
onTagsEditEnable() {
|
|
this.$data.appliedTagIds = this.currentWorkflowTagIds;
|
|
this.$data.isTagsEditEnabled = true;
|
|
|
|
setTimeout(() => {
|
|
// allow name update to occur before disabling name edit
|
|
this.$data.isNameEditEnabled = false;
|
|
this.$data.tagsEditBus.$emit('focus');
|
|
}, 0);
|
|
},
|
|
async onTagsUpdate(tags: string[]) {
|
|
this.$data.appliedTagIds = tags;
|
|
},
|
|
|
|
async onTagsBlur() {
|
|
const current = this.currentWorkflowTagIds;
|
|
const tags = this.$data.appliedTagIds;
|
|
if (!hasChanged(current, tags)) {
|
|
this.$data.isTagsEditEnabled = false;
|
|
|
|
return;
|
|
}
|
|
if (this.$data.tagsSaving) {
|
|
return;
|
|
}
|
|
this.$data.tagsSaving = true;
|
|
|
|
const saved = await this.saveCurrentWorkflow({ tags });
|
|
this.$telemetry.track('User edited workflow tags', { workflow_id: this.currentWorkflowId as string, new_tag_count: tags.length });
|
|
|
|
this.$data.tagsSaving = false;
|
|
if (saved) {
|
|
this.$data.isTagsEditEnabled = false;
|
|
}
|
|
},
|
|
onTagsEditEsc() {
|
|
this.$data.isTagsEditEnabled = false;
|
|
},
|
|
onNameToggle() {
|
|
this.$data.isNameEditEnabled = !this.$data.isNameEditEnabled;
|
|
if (this.$data.isNameEditEnabled) {
|
|
if (this.$data.isTagsEditEnabled) {
|
|
// @ts-ignore
|
|
this.onTagsBlur();
|
|
}
|
|
|
|
this.$data.isTagsEditEnabled = false;
|
|
}
|
|
},
|
|
async onNameSubmit(name: string, cb: (saved: boolean) => void) {
|
|
const newName = name.trim();
|
|
if (!newName) {
|
|
this.$showMessage({
|
|
title: "Name missing",
|
|
message: `Please enter a name, or press 'esc' to go back to the old one.`,
|
|
type: "error",
|
|
});
|
|
|
|
cb(false);
|
|
return;
|
|
}
|
|
|
|
if (newName === this.workflowName) {
|
|
this.$data.isNameEditEnabled = false;
|
|
|
|
cb(true);
|
|
return;
|
|
}
|
|
|
|
const saved = await this.saveCurrentWorkflow({ name });
|
|
if (saved) {
|
|
this.$data.isNameEditEnabled = false;
|
|
}
|
|
cb(saved);
|
|
},
|
|
},
|
|
watch: {
|
|
currentWorkflowId() {
|
|
this.$data.isTagsEditEnabled = false;
|
|
this.$data.isNameEditEnabled = false;
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
$--text-line-height: 24px;
|
|
$--header-spacing: 20px;
|
|
|
|
.container {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.name-container {
|
|
margin-right: $--header-spacing;
|
|
}
|
|
|
|
.name {
|
|
color: $--custom-font-dark;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.activator {
|
|
color: $--custom-font-dark;
|
|
font-weight: 400;
|
|
font-size: 13px;
|
|
line-height: $--text-line-height;
|
|
display: flex;
|
|
align-items: center;
|
|
margin-right: 30px;
|
|
|
|
> span {
|
|
margin-right: 5px;
|
|
}
|
|
}
|
|
|
|
.add-tag {
|
|
font-size: 12px;
|
|
padding: 20px 0; // to be more clickable
|
|
color: $--custom-font-very-light;
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
|
|
&:hover {
|
|
color: $--color-primary;
|
|
}
|
|
}
|
|
|
|
.tags {
|
|
flex: 1;
|
|
padding-right: 20px;
|
|
margin-right: $--header-spacing;
|
|
}
|
|
|
|
.tags-edit {
|
|
min-width: 100px;
|
|
max-width: 460px;
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
</style>
|