Skip to content

Commit

Permalink
feat(ui): dynamic documentation in the editor (#1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skraye authored Mar 13, 2023
1 parent 08018dd commit 4bd1ba2
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 19 deletions.
43 changes: 36 additions & 7 deletions ui/src/components/flows/TaskEdit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@
:section="section"
/>
</el-tab-pane>
<el-tab-pane v-if="pluginMardown" name="documentation">
<template #label>
<span>
{{ $t('documentation.documentation') }}
</span>
</template>
<div class="documentation">
<markdown :source="pluginMardown" />
</div>
</el-tab-pane>
</el-tabs>
</el-drawer>
</component>
Expand All @@ -74,9 +84,10 @@
import {canSaveFlowTemplate, saveFlowTemplate} from "../../utils/flowTemplate";
import {mapState} from "vuex";
import Utils from "../../utils/utils";
import Markdown from "../layout/Markdown.vue";
export default {
components: {Editor, TaskEditor},
components: {Editor, TaskEditor, Markdown},
emits: ["update:task"],
props: {
component: {
Expand Down Expand Up @@ -131,12 +142,12 @@
},
mapSectionWithSchema() {
switch (this.section) {
case "tasks":
return "task";
case "triggers":
return "trigger";
default:
return "task";
case "tasks":
return "task";
case "triggers":
return "trigger";
default:
return "task";
}
},
saveTask() {
Expand Down Expand Up @@ -173,6 +184,10 @@
} else {
this.taskYaml = YamlUtils.stringify(this.task);
}
if(this.task.type) {
this.$store
.dispatch("plugin/load", {cls: this.task.type})
}
},
},
data() {
Expand All @@ -190,6 +205,14 @@
...mapState("flow", ["flow"]),
...mapState("auth", ["user"]),
...mapState("flow", ["revisions"]),
...mapState("flow", ["revisions"]),
...mapState("plugin", ["plugin"]),
pluginMardown() {
if(this.plugin && this.plugin.markdown) {
return this.plugin.markdown
}
return null
},
canSave() {
return canSaveFlowTemplate(true, this.user, {namespace: this.namespace}, "flow");
},
Expand All @@ -202,3 +225,9 @@
}
};
</script>
<style scoped lang="scss">
// Required, otherwise the doc titles and properties names are not visible
.documentation {
padding: var(--spacer);
}
</style>
70 changes: 66 additions & 4 deletions ui/src/components/inputs/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
<el-button :icon="icon.Help" @click="restartGuidedTour" size="small" />
</el-tooltip>
</el-button-group>
<span v-if="!this.guidedProperties.tourStarted">
<el-tooltip v-if="editorTypeDocumentation" :content="editorDocumentation ? $t('hide task documentation') : $t('show task documentation')" :persistent="false" transition="" :hide-after="0">
<el-button type="info" :icon="editorDocumentation ? icon.Close : icon.BookMultipleOutline" circle style="float: right" size="small" @click="setShowDocumentation" />
</el-tooltip>
<el-tooltip v-else :content="$t('Click on a task to show documentation')" :persistent="false" transition="" :hide-after="0">
<el-button type="info" :icon="icon.Help" circle style="float: right" size="small" @click="setShowDocumentation" />
</el-tooltip>
</span>
</nav>

<div class="editor-container" ref="container" :class="containerClass">
Expand All @@ -37,6 +45,9 @@
{{ placeholder }}
</div>
</div>
<div v-if="!this.guidedProperties.tourStarted" :class="[editorTypeDocumentation && plugin && editorDocumentation ? 'plugin-doc-active' : '','plugin-doc']">
<markdown v-if="plugin" :source="plugin.markdown" />
</div>
</div>
</div>
</template>
Expand All @@ -46,7 +57,11 @@
import UnfoldLessHorizontal from "vue-material-design-icons/UnfoldLessHorizontal.vue";
import UnfoldMoreHorizontal from "vue-material-design-icons/UnfoldMoreHorizontal.vue";
import Help from "vue-material-design-icons/Help.vue";
import {mapGetters} from "vuex";
import {mapGetters, mapState} from "vuex";
import yamlUtils from "../../utils/yamlUtils";
import Markdown from "../layout/Markdown.vue";
import BookMultipleOutline from "vue-material-design-icons/BookMultipleOutline.vue";
import Close from "vue-material-design-icons/Close.vue";
const MonacoEditor = defineAsyncComponent(() =>
import("./MonacoEditor.vue")
Expand All @@ -66,10 +81,11 @@
diffSideBySide: {type: Boolean, default: true},
readOnly: {type: Boolean, default: false},
lineNumbers: {type: Boolean, default: undefined},
minimap: {type: Boolean, default: true},
minimap: {type: Boolean, default: false},
},
components: {
MonacoEditor,
Markdown
},
emits: ["save", "focusout", "tab", "update:modelValue"],
editor: undefined,
Expand All @@ -80,11 +96,16 @@
UnfoldLessHorizontal: shallowRef(UnfoldLessHorizontal),
UnfoldMoreHorizontal: shallowRef(UnfoldMoreHorizontal),
Help: shallowRef(Help),
BookMultipleOutline: shallowRef(BookMultipleOutline),
Close: shallowRef(Close)
},
oldDecorations: [],
editorDocumentation: undefined
};
},
computed: {
...mapState("plugin", ["plugin","pluginSingleList","editorTypeDocumentation"]),
...mapGetters("core", ["guidedProperties"]),
themeComputed() {
const darkTheme = document.getElementsByTagName("html")[0].className.indexOf("dark") >= 0;
Expand Down Expand Up @@ -171,8 +192,11 @@
},
...options
};
},
...mapGetters("core", ["guidedProperties"]),
}
},
created() {
this.$store.dispatch("plugin/list");
this.editorDocumentation = localStorage.getItem("editorDocumentation") !== "false" && this.navbar;
},
methods: {
editorDidMount(editor) {
Expand Down Expand Up @@ -287,6 +311,21 @@
this.oldDecorations = this.editor.deltaDecorations(this.oldDecorations, []);
}
});
this.editor.onDidChangeCursorPosition(e => {
let position = this.editor.getPosition();
let model = this.editor.getModel();
const taskType = yamlUtils.getTaskType(model.getValue(),position)
if (taskType && this.pluginSingleList.includes(taskType)) {
if(localStorage.getItem("editorDocumentation") !== "false") {
this.$store
.dispatch("plugin/load", {cls: taskType})
}
this.$store.commit("plugin/setEditorTypeDocumentation", taskType);
} else {
this.$store.commit("plugin/setEditorTypeDocumentation", undefined);
}
});
},
autoFold(autoFold) {
if (autoFold) {
Expand Down Expand Up @@ -316,6 +355,14 @@
);
this.$tours["guidedTour"].start();
},
setShowDocumentation() {
this.editorDocumentation = !this.editorDocumentation;
localStorage.setItem("editorDocumentation", (this.editorDocumentation).toString());
if(this.editorTypeDocumentation) {
this.$store
.dispatch("plugin/load", {cls: this.editorTypeDocumentation})
}
}
},
};
</script>
Expand Down Expand Up @@ -371,6 +418,7 @@
}
.editor-wrapper {
min-width: 75%;
width: 100%;
position: relative;
Expand Down Expand Up @@ -424,4 +472,18 @@
color: grey !important;
}
.plugin-doc {
position: relative;
overflow-x: hidden;
width: 0px;
margin: 0px;
padding: 0px;
transition: width var(--el-transition-duration) ease-in-out,padding var(--el-transition-duration) ease-in-out;
}
.plugin-doc-active {
width: 30%;
padding: calc(var(--spacer)*1.5);
}
</style>
6 changes: 4 additions & 2 deletions ui/src/components/layout/Markdown.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div>
<span v-html="markdownRenderer" />
<span class="markdown" v-html="markdownRenderer" />
</div>
</template>

Expand Down Expand Up @@ -47,9 +47,11 @@

<style lang="scss">
.markdown {
font-size: var(--font-size-sm);
a.header-anchor {
color: var(--bs-gray-600);
font-size: var(--font-size-base);
font-size: var(--font-size-md);
font-weight: normal;
}
}
Expand Down
14 changes: 13 additions & 1 deletion ui/src/components/settings/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
{{ $t('export all templates') }}
</el-button>
</el-form-item>

<el-form-item :label="$t('show documentation')">
<el-checkbox :label="$t('show task documentation in editor')" :model-value="editorDocumentation" @update:model-value="onEditorDocumentation" />
</el-form-item>
</el-form>
</div>
</template>
Expand Down Expand Up @@ -85,7 +89,8 @@
theme: undefined,
editorTheme: undefined,
autofoldTextEditor: undefined,
guidedTour: undefined
guidedTour: undefined,
editorDocumentation: undefined
};
},
created() {
Expand All @@ -98,6 +103,7 @@
this.editorTheme = localStorage.getItem("editorTheme") || (darkTheme ? "dark" : "vs");
this.autofoldTextEditor = localStorage.getItem("autofoldTextEditor") === "true";
this.guidedTour = localStorage.getItem("tourDoneOrSkip") === "true";
this.editorDocumentation = localStorage.getItem("editorDocumentation") !== "false";
},
methods: {
onNamespaceSelect(value) {
Expand Down Expand Up @@ -142,6 +148,12 @@
this.autofoldTextEditor = value;
this.$toast().saved();
},
onEditorDocumentation(value){
localStorage.setItem("editorDocumentation", value);
this.editorDocumentation = value;
this.$toast().saved();
}
},
computed: {
...mapGetters("core", ["guidedProperties"]),
Expand Down
12 changes: 10 additions & 2 deletions ui/src/stores/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ export default {
state: {
plugin: undefined,
plugins: undefined,
icons: undefined
pluginSingleList: undefined,
icons: undefined,
editorTypeDocumentation: undefined
},
actions: {
list({commit}) {
return this.$http.get("/api/v1/plugins", {}).then(response => {
commit("setPlugins", response.data)

commit("setPluginSingleList", response.data.map(plugin => plugin.tasks.concat(plugin.triggers, plugin.conditions, plugin.controllers, plugin.storages)).flat())
return response.data;
})
},
Expand Down Expand Up @@ -40,9 +42,15 @@ export default {
setPlugins(state, plugins) {
state.plugins = plugins
},
setPluginSingleList(state, pluginSingleList) {
state.pluginSingleList = pluginSingleList
},
setIcons(state, icons) {
state.icons = icons
},
setEditorTypeDocumentation(state, editorTypeDocumentation) {
state.editorTypeDocumentation = editorTypeDocumentation
}
},
getters: {}
}
Expand Down
12 changes: 10 additions & 2 deletions ui/src/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,11 @@
"watch demo": "Watch our Demo Video",
"watch demo content": "Get a glimpse of Kestra's power with our demo video.",
"need help?": "Need help?",
"need help? content": "Need assistance with a specific feature or flow? Our community of data engineers and developers are here to help."
"need help? content": "Need assistance with a specific feature or flow? Our community of data engineers and developers are here to help.",
"show task documentation": "Show Task documentation",
"hide task documentation": "Hide Task documentation",
"show task documentation in editor": "Show Task documentation in editor",
"show documentation": "Show documentation"
},
"fr": {
"id": "Identifiant",
Expand Down Expand Up @@ -750,6 +754,10 @@
"watch demo": "Voir notre démo",
"watch demo content": "Obtenez un aperçu de la puissance de Kestra grâce à notre vidéo de démonstration.",
"need help?": "Besoin d'aide?",
"need help? content": "Besoin d'assistance pour une fonctionnalité ou un flow? Notre communauté d'ingénieurs data et de développeurs sont là pour aider."
"need help? content": "Besoin d'assistance pour une fonctionnalité ou un flow? Notre communauté d'ingénieurs data et de développeurs sont là pour aider.",
"show task documentation": "Show Task documentation",
"hide task documentation": "Hide Task documentation",
"show task documentation in editor": "Show Task documentation in editor",
"show documentation": "Show documentation"
}
}
33 changes: 32 additions & 1 deletion ui/src/utils/yamlUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import JsYaml from "js-yaml";
import yaml, {Document, YAMLMap} from "yaml";
import yaml, {Document, LineCounter, Pair, YAMLMap, YAMLSeq} from "yaml";
import _cloneDeep from "lodash/cloneDeep"

const TOSTRING_OPTIONS = {lineWidth: 0};
Expand Down Expand Up @@ -161,4 +161,35 @@ export default class YamlUtils {

return index === -1 ? Number.MAX_SAFE_INTEGER : index;
}

static getTaskType(source, position) {
const lineCounter = new LineCounter();
const yamlDoc = yaml.parseDocument(source, {lineCounter});
const cursorIndex = lineCounter.lineStarts[position.lineNumber-1] + position.column;
for(const item of yamlDoc.contents.items){
if(item.value instanceof YAMLSeq && item.key.range[0] <= cursorIndex && item.value.range[1] >= cursorIndex){
return YamlUtils._getTaskType(item.value, cursorIndex, null)
}
}
}

static _getTaskType(element, cursorIndex, previousTaskType){
let taskType = previousTaskType
for(const item of element.items){
if(item instanceof Pair){
if(item.key.value === "type" && element.range[0] <= cursorIndex && element.range[1] >= cursorIndex){
taskType = item.value.value
}
if((item.value instanceof YAMLSeq || item.value instanceof YAMLMap) && item.value.range[0] <= cursorIndex && item.value.range[1] >= cursorIndex){
taskType = this._getTaskType(item.value, cursorIndex, taskType)
}
}
else if(item.range[0] <= cursorIndex && item.range[1] >= cursorIndex){
if(item.items instanceof Array){
taskType = this._getTaskType(item, cursorIndex)
}
}
}
return taskType
}
}

0 comments on commit 4bd1ba2

Please sign in to comment.