Skip to content

Commit 69001be

Browse files
committed
feat(ui): replace legacy product tour with onboarding v2 and unify onboarding i18n keys
remove legacy VueTour flow and obsolete onboarding button components wire onboarding v2 guided/self-serve flow in create/edit journey migrate first-flow copy to onboarding.* and clean unused en translation keys update onboarding and flow-save unit tests
1 parent 88ab3c2 commit 69001be

38 files changed

+1805
-1097
lines changed

ui/package-lock.json

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
"vue-sidebar-menu": "^5.9.1",
7373
"vue-virtual-scroller": "^2.0.0-beta.8",
7474
"vue3-popper": "^1.5.0",
75-
"vue3-tour": "github:kestra-io/vue3-tour",
7675
"xss": "^1.0.15",
7776
"yaml": "^2.8.2"
7877
},

ui/src/App.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<component :is="route.meta.layout ?? DefaultLayout" v-if="loaded && shouldRenderApp">
66
<router-view />
77
</component>
8-
<VueTour v-if="shouldRenderApp && route?.name && !route.meta?.anonymous" />
8+
<OnboardingOverlay v-if="shouldRenderApp && route?.name && !route.meta?.anonymous" />
99
<UnsavedChangesDialog />
1010
</el-config-provider>
1111
</template>
@@ -22,7 +22,7 @@
2222
import * as BasicAuth from "./utils/basicAuth";
2323
import {initPosthogIfEnabled} from "./utils/posthog";
2424
import ErrorToast from "./components/ErrorToast.vue";
25-
import VueTour from "./components/onboarding/VueTour.vue";
25+
import OnboardingOverlay from "./components/onboarding/OnboardingOverlay.vue";
2626
import DefaultLayout from "override/components/layout/DefaultLayout.vue";
2727
import DocIdDisplay from "./components/DocIdDisplay.vue";
2828
import UnsavedChangesDialog from "./components/UnsavedChangesDialog.vue";

ui/src/components/executions/ExecutionRootTopBar.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<div class="d-flex align-items-center gap-2" v-if="(isAllowedEdit || isAllowedTrigger) && $route.params.tab !== 'audit-logs'">
1010
<ul class="d-none d-xl-flex align-items-center">
1111
<li v-if="isAllowedEdit">
12-
<el-button :icon="Pencil" @click="editFlow">
12+
<el-button class="execution-edit-flow-button" :icon="Pencil" @click="editFlow">
1313
{{ $t("edit flow") }}
1414
</el-button>
1515
</li>
@@ -106,4 +106,4 @@
106106
}
107107
}
108108
109-
</style>
109+
</style>

ui/src/components/flows/FlowCreate.vue

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,29 @@
1313
import TopNavBar from "../../components/layout/TopNavBar.vue";
1414
import MultiPanelFlowEditorView from "./MultiPanelFlowEditorView.vue";
1515
import {useBlueprintsStore} from "../../stores/blueprints";
16-
import {useCoreStore} from "../../stores/core";
1716
import {getRandomID} from "../../../scripts/id";
1817
import {useFlowStore} from "../../stores/flow";
1918
import {defaultNamespace} from "../../composables/useNamespaces";
20-
import {useVueTour} from "../../composables/useVueTour";
2119
2220
import type {BlueprintType} from "../../stores/blueprints"
2321
import {useAuthStore} from "../../override/stores/auth";
2422
import permission from "../../models/permission";
2523
import action from "../../models/action";
24+
import {useOnboardingV2Store} from "../../stores/onboardingV2";
2625
2726
const route = useRoute();
2827
const {t} = useI18n();
2928
30-
const tour = useVueTour("guidedTour");
31-
3229
const blueprintsStore = useBlueprintsStore();
33-
const coreStore = useCoreStore();
3430
const flowStore = useFlowStore();
3531
const authStore = useAuthStore();
32+
const onboardingV2Store = useOnboardingV2Store();
3633
3734
const setupFlow = async () => {
3835
const blueprintId = route.query.blueprintId as string;
3936
const blueprintSource = route.query.blueprintSource as BlueprintType;
4037
const blueprintSourceYaml = route.query.blueprintSourceYaml as string;
38+
const isGuidedOnboarding = route.query.onboarding === "guided";
4139
const implicitDefaultNamespace = authStore.user.getNamespacesForAction(
4240
permission.FLOW,
4341
action.CREATE,
@@ -62,6 +60,8 @@
6260
} else if (blueprintId) {
6361
const flowBlueprint = await blueprintsStore.getFlowBlueprint(blueprintId);
6462
flowYaml = flowBlueprint.source;
63+
} else if (isGuidedOnboarding) {
64+
flowYaml = `# ${t("onboarding.editor_hints.build_intro")}\n`;
6565
} else {
6666
flowYaml = `
6767
id: ${id}
@@ -73,10 +73,17 @@ tasks:
7373
message: Hello World! 🚀`.trim();
7474
}
7575
76+
let parsedFlow = {};
77+
try {
78+
parsedFlow = YAML_UTILS.parse(flowYaml) ?? {};
79+
} catch {
80+
parsedFlow = {};
81+
}
82+
7683
flowStore.flow = {
7784
id,
7885
namespace: selectedNamespace,
79-
...YAML_UTILS.parse(flowYaml),
86+
...parsedFlow,
8087
source: flowYaml,
8188
};
8289
@@ -90,13 +97,8 @@ tasks:
9097
});
9198
9299
flowStore.isCreating = true;
93-
if (route.query.reset) {
94-
localStorage.setItem("tourDoneOrSkip", "");
95-
coreStore.guidedProperties = {
96-
...coreStore.guidedProperties,
97-
tourStarted: true,
98-
};
99-
tour.start();
100+
if (route.query.reset || route.query.onboarding === "guided") {
101+
onboardingV2Store.startGuided();
100102
}
101103
setupFlow();
102104

ui/src/components/flows/FlowRoot.vue

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import FlowExecutions from "./FlowExecutions.vue";
2121
import RouteContext from "../../mixins/routeContext";
2222
import {mapStores} from "pinia";
23-
import {useCoreStore} from "../../stores/core";
2423
import {useFlowStore} from "../../stores/flow";
2524
import permission from "../../models/permission";
2625
import action from "../../models/action";
@@ -70,18 +69,6 @@
7069
}
7170
}
7271
},
73-
"coreStore.guidedProperties": {
74-
deep: true,
75-
immediate: true,
76-
handler: function (newValue) {
77-
if (newValue?.manuallyContinue) {
78-
setTimeout(() => {
79-
this.$tours["guidedTour"]?.nextStep();
80-
this.coreStore.guidedProperties = {...this.coreStore.guidedProperties, manuallyContinue: false};
81-
}, 500);
82-
}
83-
},
84-
},
8572
"flowStore.flow": {
8673
deep: true,
8774
handler: function (flow) {
@@ -314,7 +301,7 @@
314301
}
315302
},
316303
computed: {
317-
...mapStores(useCoreStore, useFlowStore, useAuthStore, useMiscStore),
304+
...mapStores(useFlowStore, useAuthStore, useMiscStore),
318305
routeInfo() {
319306
return {
320307
title: this.$route.params.id,
@@ -362,4 +349,4 @@
362349
.body-color {
363350
color: var(--ks-content-primary);
364351
}
365-
</style>
352+
</style>

ui/src/components/flows/FlowRun.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
<el-button
6262
:icon="buttonIcon"
6363
:disabled="!flowCanBeExecuted || hasBlockingChecks()"
64-
:class="{'flow-run-trigger-button': true, 'onboarding-glow': coreStore.guidedProperties.tourStarted}"
64+
class="flow-run-trigger-button"
6565
type="primary"
6666
nativeType="submit"
6767
@click.prevent="onSubmit($refs.form); executeClicked = true;"

ui/src/components/flows/MultiPanelFlowEditorView.vue

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<MultiPanelGenericEditorView
33
ref="editorView"
44
:class="{playgroundMode}"
5-
:editorElements="EDITOR_ELEMENTS"
6-
:defaultActiveTabs="TABS"
5+
:editorElements="editorElements"
6+
:defaultActiveTabs="tabs"
77
:saveKey
88
:preSerializePanels="preSerializePanels"
99
:bottomVisible="playgroundMode"
@@ -25,8 +25,8 @@
2525
import {computed, markRaw, onMounted, onUnmounted, ref, watch} from "vue";
2626
import {useRoute} from "vue-router";
2727
import Utils from "../../utils/utils";
28-
import {useCoreStore} from "../../stores/core";
2928
import {usePlaygroundStore} from "../../stores/playground";
29+
import {useOnboardingV2Store} from "../../stores/onboardingV2";
3030
3131
import FlowPlayground from "./FlowPlayground.vue";
3232
import EditorButtonsWrapper from "../inputs/EditorButtonsWrapper.vue";
@@ -51,7 +51,7 @@
5151
5252
const RawNoCode = markRaw(NoCode)
5353
54-
const coreStore = useCoreStore()
54+
const onboardingV2Store = useOnboardingV2Store()
5555
const flowStore = useFlowStore()
5656
const {showKeyShortcuts} = useKeyShortcuts()
5757
@@ -95,9 +95,6 @@
9595
9696
useInitialFilesTabs(EDITOR_ELEMENTS)
9797
98-
const isTourRunning = computed(() => coreStore.guidedProperties?.tourStarted)
99-
const DEFAULT_TOUR_TABS = ["code", "topology"];
100-
10198
function cleanupNoCodeTabKey(key: string): string {
10299
// remove the number for "nocode-1234-" prefix from the key
103100
return /^nocode-\d{4}/.test(key) ? key.slice(0, 6) + key.slice(11) : key
@@ -122,7 +119,18 @@
122119
source: computed(() => flowStore.flowYaml),
123120
});
124121
125-
const TABS = isTourRunning.value ? DEFAULT_TOUR_TABS : DEFAULT_ACTIVE_TABS;
122+
const isGuidedCodeOnly = computed(
123+
() => onboardingV2Store.isGuidedActive && onboardingV2Store.state.editorMode === "code_only",
124+
);
125+
watch(isGuidedCodeOnly, (guided) => {
126+
if (guided && playgroundStore.enabled) {
127+
playgroundStore.enabled = false;
128+
}
129+
}, {immediate: true});
130+
const editorElements = computed(() => (isGuidedCodeOnly.value
131+
? EDITOR_ELEMENTS.filter((element) => element.uid === "code")
132+
: EDITOR_ELEMENTS));
133+
const tabs = computed(() => (isGuidedCodeOnly.value ? ["code"] : DEFAULT_ACTIVE_TABS));
126134
127135
flowStore.creationId = flowStore.creationId ?? Utils.uid()
128136

ui/src/components/flows/TriggerFlow.vue

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
<el-button v-if="playgroundStore.enabled" id="run-all-button" :icon="icon.Play" class="el-button--playground" :disabled="isDisabled() || !playgroundStore.readyToStart" @click="playgroundStore.runUntilTask()">
44
{{ $t("playground.run_all_tasks") }}
55
</el-button>
6-
<el-button v-else id="execute-button" :class="{'onboarding-glow': coreStore.guidedProperties.glowExecuteButton}" :icon="icon.Play" :type="type" :disabled="isDisabled()" @click="onClick()">
6+
<el-button v-else id="execute-button" :icon="icon.Play" :type="type" :disabled="isDisabled()" @click="onClick()">
77
{{ $t("execute") }}
88
</el-button>
99
<el-dialog
1010
id="execute-flow-dialog"
1111
v-model="isOpen"
1212
destroyOnClose
13-
:showClose="!coreStore.guidedProperties.tourStarted"
13+
:showClose="true"
1414
:beforeClose="(done) => beforeClose(done)"
1515
:appendToBody="true"
1616
:width="dialogWidth"
@@ -75,11 +75,9 @@
7575
import Play from "vue-material-design-icons/Play.vue";
7676
import {shallowRef} from "vue";
7777
import {useMediaQuery} from "@vueuse/core";
78-
import {pageFromRoute} from "../../utils/eventsRouter";
7978
import FlowWarningDialog from "./FlowWarningDialog.vue";
8079
import {mapStores} from "pinia";
8180
import {useApiStore} from "../../stores/api";
82-
import {useCoreStore} from "../../stores/core";
8381
import {useExecutionsStore} from "../../stores/executions";
8482
import {usePlaygroundStore} from "../../stores/playground";
8583
import {useFlowStore} from "../../stores/flow";
@@ -135,21 +133,7 @@
135133
},
136134
onClick() {
137135
this.trackExecutionAction("open_modal");
138-
if (this.$tours["guidedTour"]?.isRunning?.value) {
139-
this.$tours["guidedTour"]?.nextStep();
140-
this.apiStore.events({
141-
type: "ONBOARDING",
142-
onboarding: {
143-
step: this.$tours["guidedTour"]?.currentStep?._value,
144-
action: "next",
145-
template: this.coreStore.guidedProperties.template
146-
},
147-
page: pageFromRoute(this.$router.currentRoute.value)
148-
});
149-
this.toggleModal()
150-
return;
151-
}
152-
else if (this.checkForTrigger) {
136+
if (this.checkForTrigger) {
153137
this.$toast().confirm(FlowWarningDialog, () => (this.toggleModal()), true, null);
154138
}
155139
else if (this.computedNamespace !== undefined && this.computedFlowId !== undefined) {
@@ -190,14 +174,12 @@
190174
this.localNamespace = undefined;
191175
},
192176
beforeClose(done){
193-
if(this.coreStore.guidedProperties.tourStarted) return;
194-
195177
this.reset();
196178
done()
197179
}
198180
},
199181
computed: {
200-
...mapStores(useApiStore, useCoreStore, useExecutionsStore, usePlaygroundStore, useFlowStore),
182+
...mapStores(useApiStore, useExecutionsStore, usePlaygroundStore, useFlowStore),
201183
dialogWidth() {
202184
return this.isLargeScreen ? "50%" : "90%";
203185
},
@@ -216,14 +198,6 @@
216198
}
217199
},
218200
watch: {
219-
"coreStore.guidedProperties": {
220-
handler() {
221-
if (this.coreStore.guidedProperties.executeFlow) {
222-
this.onClick();
223-
}
224-
},
225-
deep: true
226-
},
227201
"flowStore.executeFlow": {
228202
handler(value) {
229203
if (value && !this.isDisabled()) {
@@ -270,18 +244,4 @@
270244
.trigger-flow-wrapper {
271245
display: inline;
272246
}
273-
274-
.onboarding-glow {
275-
animation: glowAnimation 1s infinite alternate;
276-
}
277-
278-
279-
@keyframes glowAnimation {
280-
0% {
281-
box-shadow: 0px 0px 0px 0px #8405FF;
282-
}
283-
100% {
284-
box-shadow: 0px 0px 50px 2px #8405FF;
285-
}
286-
}
287247
</style>

0 commit comments

Comments
 (0)