Skip to content

Commit

Permalink
feat(ui): introduce the revamped no code editor (#6787)
Browse files Browse the repository at this point in the history
  • Loading branch information
MilosPaunovic authored Jan 15, 2025
1 parent 81a4e86 commit 821fd12
Show file tree
Hide file tree
Showing 51 changed files with 1,457 additions and 577 deletions.
22 changes: 17 additions & 5 deletions ui/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";

const components = (folder) => `src/components/${folder}/**/*.vue`;

/** @type {import('eslint').Linter.Config[]} */
export default [
{
Expand All @@ -12,8 +14,13 @@ export default [
{languageOptions: {globals: globals.browser}},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
files: ["**/*.spec.js", "**/*.spec.ts", "vite.config.js", "vitest.config.js"],
{
files: [
"**/*.spec.js",
"**/*.spec.ts",
"vite.config.js",
"vitest.config.js",
],
languageOptions: {globals: globals.node},
},
...pluginVue.configs["flat/strongly-recommended"],
Expand Down Expand Up @@ -66,7 +73,12 @@ export default [
},
],
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-explicit-any": "off"
}
}
"@typescript-eslint/no-explicit-any": "off",
},
},
{
// Enforce the use of the <script setup> block in components within these paths
files: [components("filter"), components("code")],
rules: {"vue/component-api-style": ["error", ["script-setup"]]},
},
];
2 changes: 1 addition & 1 deletion ui/src/components/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
.filter(tab => (this.embedActiveTab ?? this.$route.params.tab) === tab.name)[0] || this.tabs[0];
},
isEditorActiveTab() {
return this.activeTab.name === "editor";
return this.activeTab.name === "edit";
},
isNamespaceEditor(){
return this.activeTab?.props?.isNamespace === true;
Expand Down
54 changes: 54 additions & 0 deletions ui/src/components/code/NoCode.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<div class="h-100 overflow-y-auto no-code">
<Breadcrumbs :flow="YamlUtils.parse(props.flow)" />

<hr class="m-0">

<Editor
:creation="route.query.identifier === 'new'"
:flow
:metadata
:schemas
@update-metadata="(k, v) => emits('updateMetadata', {[k]: v})"
@update-task="(yaml) => emits('updateTask', yaml)"
/>
</div>
</template>

<script setup lang="ts">
import {onBeforeMount, computed, ref} from "vue";
import {Schemas} from "./utils/types";
import YamlUtils from "../../utils/yamlUtils";
import Breadcrumbs from "./components/Breadcrumbs.vue";
import Editor from "./segments/Editor.vue";
const emits = defineEmits(["updateTask", "updateMetadata"]);
const props = defineProps({
flow: {type: String, required: true},
});
const metadata = computed(() => YamlUtils.getMetadata(props.flow));
import {useStore} from "vuex";
const store = useStore();
import {useRouter, useRoute} from "vue-router";
const router = useRouter();
const route = useRoute();
const schemas = ref<Schemas>({});
onBeforeMount(async () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {section, identifier, type, ...rest} = route.query;
router.replace({query: {...rest}});
schemas.value = await store.dispatch("plugin/loadSchemaType");
});
</script>

<style scoped lang="scss">
@import "./styles/code.scss";
</style>
5 changes: 5 additions & 0 deletions ui/src/components/code/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Guide on How to Handle the `NoCode` Editor

> Code within `Vue` components must be written using the `<script setup>` block, as enforced by the `ESLint` rule.
This is a brief guide on working with the `NoCode` editor component.
23 changes: 23 additions & 0 deletions ui/src/components/code/components/Add.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div @click="emits('add', props.what)" class="pb-3 adding">
{{ t("no_code.adding", {what: props.what}) }}
</div>
</template>

<script setup lang="ts">
import {useI18n} from "vue-i18n";
const {t} = useI18n({useScope: "global"});
const emits = defineEmits(["add"]);
const props = defineProps({what: {type: String, required: true}});
</script>

<style scoped lang="scss">
@import "../styles/code.scss";
.adding {
cursor: pointer;
color: $code-gray-700;
font-size: $code-font-sm;
}
</style>
61 changes: 61 additions & 0 deletions ui/src/components/code/components/Breadcrumbs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<el-breadcrumb class="p-4">
<el-breadcrumb-item
v-for="(breadcrumb, index) in breadcrumbs"
:key="index"
class="item"
>
<router-link :to="breadcrumb.to">
{{ breadcrumb.label }}
</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</template>

<script setup lang="ts">
import {computed} from "vue";
import {Breadcrumb} from "../utils/types";
import {useRoute} from "vue-router";
const route = useRoute();
import {useI18n} from "vue-i18n";
const {t} = useI18n({useScope: "global"});
const props = defineProps({flow: {type: Object, required: true}});
const params = {
namespace: route.params.namespace,
id: props.flow.id ?? "new",
tab: "edit",
};
const breadcrumbs = computed<Breadcrumb[]>(() => {
return [
{
label: props.flow.id ?? t("create_flow"),
to: {name: route.name, params},
},
...(route.query.section
? [
{
label:
route.query.identifier === "new"
? t(`no_code.creation.${route.query.section}`)
: route.query.identifier,
to: {name: route.name, params},
},
]
: []),
];
});
</script>

<style scoped lang="scss">
@import "../styles/code.scss";
.item:last-child > .el-breadcrumb__inner > a {
color: $code-primary !important;
}
</style>
16 changes: 16 additions & 0 deletions ui/src/components/code/components/Save.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<el-button type="primary" :icon="ContentSave">
{{ t(`no_code.save.${props.what}`) }}
</el-button>
</template>

<script setup lang="ts">
import {ContentSave} from "../utils/icons";
const props = defineProps({
what: {type: String, required: true, default: "tasks"},
});
import {useI18n} from "vue-i18n";
const {t} = useI18n({useScope: "global"});
</script>
79 changes: 79 additions & 0 deletions ui/src/components/code/components/collapse/Collapse.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<el-collapse v-model="expanded" class="mt-3 collapse">
<el-collapse-item
v-for="(item, index) in props.items"
:key="index"
:name="item.title"
:title="`${item.title}${item.elements ? ` (${item.elements.length})` : ''}`"
:class="{creation: props.creation}"
>
<template v-if="creation" #icon>
<Creation :section="item.title" />
</template>

<template v-if="creation">
<Element
v-for="(element, elementIndex) in item.elements"
:key="elementIndex"
:section="item.title"
:element
/>
</template>

<slot name="content" />
</el-collapse-item>
</el-collapse>
</template>

<script setup lang="ts">
import {PropType, ref} from "vue";
import {CollapseItem} from "../../utils/types";
import Creation from "./buttons/Creation.vue";
import Element from "./Element.vue";
const props = defineProps({
items: {
type: Array as PropType<CollapseItem[]>,
required: true,
},
creation: {type: Boolean, default: false},
});
const expanded = ref<CollapseItem["title"][]>([]);
if (props.creation) {
props.items.forEach((item) => {
if (item.elements?.length) expanded.value.push(item.title);
});
}
</script>

<style scoped lang="scss">
@import "../../styles/code.scss";
.collapse {
& * {
font-size: $code-font-sm;
}
:deep(*) {
--el-collapse-header-bg-color: initial;
--el-collapse-header-text-color: #{$code-gray-700};
--el-collapse-content-bg-color: initial;
.el-collapse-item__header,
.el-collapse-item__content {
padding: 0.5rem 0;
}
.el-collapse-item__header {
justify-content: space-between;
&.is-active {
color: $code-primary;
}
}
}
}
</style>
62 changes: 62 additions & 0 deletions ui/src/components/code/components/collapse/Element.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<div @click="handleClick" class="d-flex my-2 p-2 rounded element">
<div class="me-2 icon">
<TaskIcon :cls="props.element.type" :icons only-icon />
</div>

<div class="flex-grow-1 label">
{{ props.element.id }}
</div>
</div>
</template>

<script setup lang="ts">
import {computed} from "vue";
// TODO: Update import once https://github.com/kestra-io/kestra/pull/6643 is merged
import TaskIcon from "@kestra-io/ui-libs/src/components/misc/TaskIcon.vue";
const props = defineProps({
section: {type: String, required: true},
element: {type: Object, required: true},
});
import {useStore} from "vuex";
const store = useStore();
const icons = computed(() => store.state.plugin.icons);
import {useRouter, useRoute} from "vue-router";
const router = useRouter();
const route = useRoute();
const handleClick = () => {
router.replace({
query: {
...route.query,
section: props.section.toLowerCase(),
identifier: props.element.id,
type: props.element.type,
},
});
};
</script>

<style scoped lang="scss">
@import "../../styles/code.scss";
.element {
cursor: pointer;
background-color: $code-card-color;
border: 1px solid $code-border-color;
& > .icon {
width: 1.25rem;
}
& > .label {
color: initial;
font-size: $code-font-sm;
}
}
</style>
28 changes: 28 additions & 0 deletions ui/src/components/code/components/collapse/buttons/Creation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<el-button @click.prevent.stop="handleClick()" type="primary" :icon="Plus">
{{ t("add") }}
</el-button>
</template>

<script setup lang="ts">
import {Plus} from "../../../utils/icons";
import {useRouter, useRoute} from "vue-router";
const router = useRouter();
const route = useRoute();
import {useI18n} from "vue-i18n";
const {t} = useI18n({useScope: "global"});
const props = defineProps({section: {type: String, required: true}});
const handleClick = () => {
router.replace({
query: {
...route.query,
section: props.section.toLowerCase(),
identifier: "new",
},
});
};
</script>
Loading

0 comments on commit 821fd12

Please sign in to comment.