mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(editor): Add user activation survey (#5677)
* ⚡ Add user activation survey
* Fix typo
* Avoid showing the modal when there is a modal view
* Allow to redirect to specific execution
* Improve structure
* Handle errors when sharing feedback
* update withFeatureFlag function
* Fix linting issue
* Set user activation flag on workflowExecutionCompleted event
* Revert update user settings functionality
* Remove unnecessary changes
* fix linting issue
* account for new functionality in tests
* Small improvements
* keep once instace of the model open between tabs
* Add sorting to GET /executions
* type parameters for GET /executions
a
* Add constant for local store key
* Add execution mode filtering
* fix linting issue
* Do not override settings when setting isOnboarded true
* Add update user settings endpoint
* improvements
* revert changes to /GET executions
* Fix typo
* Add userActivated flag to user store
* Add E2E test
* Fix linting issue
* Update pnpm-lock
* Revert unnecessary change
* Centralize user's settings update
* Remove unused ref in userActivationSurvey modal
* Use aliased imports
* Use createEventBus function in component
* Fix tests
This commit is contained in:
174
packages/editor-ui/src/components/UserActivationSurveyModal.vue
Normal file
174
packages/editor-ui/src/components/UserActivationSurveyModal.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<Modal
|
||||
width="500px"
|
||||
:title="locale.baseText('userActivationSurveyModal.title')"
|
||||
:eventBus="modalBus"
|
||||
:name="USER_ACTIVATION_SURVEY_MODAL"
|
||||
:center="true"
|
||||
:beforeClose="beforeClosingModal"
|
||||
>
|
||||
<template #content>
|
||||
<div :class="$style.container">
|
||||
<div :class="$style.description">
|
||||
<i18n path="userActivationSurveyModal.description.workflowRan">
|
||||
<template #workflow>
|
||||
<n8n-text :bold="true"> {{ workflowName }} </n8n-text>
|
||||
</template>
|
||||
<template #ranSuccessfully>
|
||||
<n8n-text :bold="true" :class="$style.link">
|
||||
{{
|
||||
locale.baseText('userActivationSurveyModal.description.workflowRanSuccessfully')
|
||||
}}
|
||||
</n8n-text>
|
||||
</template>
|
||||
<template #savedTime>
|
||||
<n8n-text>
|
||||
{{ locale.baseText('userActivationSurveyModal.description.savedTime') }}
|
||||
</n8n-text>
|
||||
</template>
|
||||
</i18n>
|
||||
</div>
|
||||
<div :class="$style.form">
|
||||
<n8n-input-label
|
||||
:label="$locale.baseText('userActivationSurveyModal.form.label')"
|
||||
color="text-dark"
|
||||
>
|
||||
<n8n-input
|
||||
type="textarea"
|
||||
:maxlength="FEEDBACK_MAX_LENGTH"
|
||||
:rows="3"
|
||||
v-model="feedback"
|
||||
@input="onInput"
|
||||
data-test-id="activation-feedback-input"
|
||||
/>
|
||||
</n8n-input-label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div :class="$style.modalFooter">
|
||||
<n8n-button
|
||||
:disabled="!hasAnyChanges"
|
||||
@click="onShareFeedback"
|
||||
size="large"
|
||||
float="right"
|
||||
:label="locale.baseText('userActivationSurveyModal.form.button.shareFeedback')"
|
||||
data-test-id="send-activation-feedback-button"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
import { USER_ACTIVATION_SURVEY_MODAL } from '@/constants';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
import confetti from 'canvas-confetti';
|
||||
import { telemetry } from '@/plugins/telemetry';
|
||||
import { i18n as locale } from '@/plugins/i18n';
|
||||
import { Notification } from 'element-ui';
|
||||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
import { createEventBus } from '@/event-bus';
|
||||
|
||||
const FEEDBACK_MAX_LENGTH = 300;
|
||||
|
||||
const userStore = useUsersStore();
|
||||
const workflowStore = useWorkflowsStore();
|
||||
|
||||
const hasAnyChanges = ref(false);
|
||||
const feedback = ref('');
|
||||
const modalBus = createEventBus();
|
||||
const workflowName = ref('');
|
||||
|
||||
onMounted(async () => {
|
||||
const currentSettings = getCurrentSettings();
|
||||
try {
|
||||
const { name } = await workflowStore.fetchWorkflow(
|
||||
currentSettings?.firstSuccessfulWorkflowId ?? '',
|
||||
);
|
||||
workflowName.value = name;
|
||||
showConfetti();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
const onShareFeedback = () => {
|
||||
telemetry.track('User responded to activation modal', { response: getFeedback() });
|
||||
showSharedFeedbackSuccess();
|
||||
modalBus.emit('close');
|
||||
};
|
||||
|
||||
const getCurrentSettings = () => {
|
||||
return userStore.currentUser?.settings;
|
||||
};
|
||||
|
||||
const getFeedback = () => {
|
||||
return feedback.value.slice(0, FEEDBACK_MAX_LENGTH);
|
||||
};
|
||||
|
||||
const beforeClosingModal = async () => {
|
||||
const currentUser = userStore.currentUser;
|
||||
if (currentUser) {
|
||||
try {
|
||||
await userStore.updateUserSettings({ showUserActivationSurvey: false });
|
||||
} catch {
|
||||
showSharedFeedbackError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const onInput = () => {
|
||||
hasAnyChanges.value = true;
|
||||
};
|
||||
|
||||
const showSharedFeedbackSuccess = () => {
|
||||
Notification.success({
|
||||
title: locale.baseText('userActivationSurveyModal.sharedFeedback.success'),
|
||||
message: '',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
};
|
||||
|
||||
const showSharedFeedbackError = () => {
|
||||
Notification.error({
|
||||
title: locale.baseText('userActivationSurveyModal.sharedFeedback.error'),
|
||||
message: '',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
};
|
||||
|
||||
const showConfetti = () => {
|
||||
confetti({
|
||||
particleCount: 200,
|
||||
spread: 100,
|
||||
origin: { y: 0.6 },
|
||||
zIndex: 2050,
|
||||
colors: ['5C4EC2', 'D7E6F1', 'FF9284', '8D7FED', 'B8AFF9', 'FF6D5A'],
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style module lang="scss">
|
||||
.form {
|
||||
margin-top: var(--spacing-l);
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.description > * {
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
|
||||
.container > * {
|
||||
margin-bottom: var(--spacing-s);
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user