Skip to content

Commit

Permalink
feat: json-schema-based plugin doc (#174)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: YannC <[email protected]>
  • Loading branch information
brian-mulier-p and Skraye authored Jan 22, 2025
1 parent e8194ff commit 16feca3
Show file tree
Hide file tree
Showing 13 changed files with 956 additions and 392 deletions.
314 changes: 280 additions & 34 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"require": "./dist/kestra-ui.umd.cjs"
},
"./style.css": "./dist/kestra-ui.css",
"./scss/*": "./src/scss/*",
"./src/*": "./src/*"
},
"scripts": {
Expand All @@ -45,6 +44,7 @@
"moment-timezone": "^0.5.46",
"vue": "^3.5.5",
"vue-material-design-icons": "^5.3.0",
"vue-router": "^4.5.0",
"vuex": "^4.1.0",
"yaml": "^2.5.1"
},
Expand Down Expand Up @@ -80,7 +80,7 @@
"@nuxtjs/mdc": "^0.12.1",
"@popperjs/core": "^2.11.8",
"mermaid": "^11.4.1",
"shiki": "^1.26.1",
"shiki": "^1.22.0",
"vue-i18n": "^11.0.1"
},
"optionalDependencies": {
Expand Down
68 changes: 68 additions & 0 deletions src/components/misc/Collapsible.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<div :id="href" class="d-flex flex-column gap-2">
<button @click="collapsed = !collapsed" class="d-flex align-items-center justify-content-between fw-bold gap-2 collapse-button" :class="{collapsed}" data-toggle="collapse" :data-target="'#' + href + '-body'" aria-expanded="false" :aria-controls="href + '-body'">
<span class="d-flex gap-2 align-items-center"><component v-if="arrow" class="arrow" :is="collapsed ? MenuRight : MenuDown" />{{ clickableText }}<slot name="additionalButtonText" /></span>
<span v-if="$slots.buttonRight" class="d-flex flex-grow-1">
<slot name="buttonRight" :collapsed="collapsed" />
</span>
</button>
<div v-if="$slots.content" v-show="!collapsed" :id="href + '-body'" class="collapsible-body">
<slot name="content" />
</div>
</div>
</template>

<script setup lang="ts">
import {ref, watch} from "vue";
import MenuRight from "vue-material-design-icons/MenuRight.vue";
import MenuDown from "vue-material-design-icons/MenuDown.vue";
import {useRoute} from "vue-router";
const props = withDefaults(defineProps<{ href?: string, clickableText: string, arrow: boolean, initiallyExpanded: boolean }>(), {
href: Math.random().toString(36).substring(2, 5),
arrow: true,
initiallyExpanded: false
});
const collapsed = ref(!props.initiallyExpanded);
const route = useRoute();
const emit = defineEmits(["expand"]);
watch(
() => {
return route.hash;
},
routeHash => {
if (routeHash === "#" + props.href) {
collapsed.value = false;
emit("expand");
}
},
{immediate: true}
);
watch(
() => props.initiallyExpanded,
initiallyExpanded => {
if (initiallyExpanded) {
collapsed.value = !initiallyExpanded;
}
},
{immediate: true}
);
</script>

<style scoped lang="scss">
.collapse-button {
padding: 0;
border: none;
background: none;
&:focus {
outline:none;
box-shadow: none;
}
}
</style>
145 changes: 145 additions & 0 deletions src/components/plugins/CollapsibleProperties.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<template>
<Collapsible :clickable-text="sectionName" :href="href" @expand="emit('expand')" :initially-expanded="initiallyExpanded">

Check failure on line 2 in src/components/plugins/CollapsibleProperties.vue

View workflow job for this annotation

GitHub Actions / Publish to Npm

Argument of type '{ clickableText: string; href: string; initiallyExpanded: boolean; onExpand: any; }' is not assignable to parameter of type '{ readonly href?: string | undefined; readonly clickableText: string; readonly arrow: boolean; readonly initiallyExpanded: boolean; readonly onExpand?: ((...args: any[]) => any) | undefined; } & ... 5 more ... & Record<...>'.
<template v-if="Object.keys(properties ?? {}).length > 0" #content>
<div class="border rounded">
<Collapsible

Check failure on line 5 in src/components/plugins/CollapsibleProperties.vue

View workflow job for this annotation

GitHub Actions / Publish to Npm

Argument of type '{ key: string; arrow: false; clickableText: string; href: string; class: string; onExpand: any; }' is not assignable to parameter of type '{ readonly href?: string | undefined; readonly clickableText: string; readonly arrow: boolean; readonly initiallyExpanded: boolean; readonly onExpand?: ((...args: any[]) => any) | undefined; } & ... 5 more ... & Record<...>'.
class="property p-3"
v-for="(property, propertyKey) in sortSchemaByRequired(properties)"

Check failure on line 7 in src/components/plugins/CollapsibleProperties.vue

View workflow job for this annotation

GitHub Actions / Publish to Npm

Argument of type '[JSONProperty]' is not assignable to parameter of type 'Record<string, JSONProperty>'.
:key="propertyKey"
:arrow="false"
:clickable-text="propertyKey"
:href="href + '_' + propertyKey"
@expand="initiallyExpanded = true"
>
<template #additionalButtonText>
<span v-if="property['$required']" class="text-danger"> *</span>
</template>
<template #buttonRight="{collapsed}">
<span class="d-flex flex-grow-1 align-items-center justify-content-between">
<span class="d-flex gap-1">
<Tooltip v-if="showDynamic && !isDynamic(property)" class="d-flex" title="Non-dynamic">
<Cancel class="text-danger" />
</Tooltip>
<Tooltip v-if="property['$beta']" class="d-flex" title="Beta">
<AlphaBBox class="text-warning" />
</Tooltip>
<Tooltip v-if="property['$deprecated']" class="d-flex" title="Deprecated">
<Alert class="text-warning" />
</Tooltip>
</span>
<span class="d-flex gap-2">
<template v-for="type in extractTypeInfo(property).types" :key="type">

Check failure on line 31 in src/components/plugins/CollapsibleProperties.vue

View workflow job for this annotation

GitHub Actions / Publish to Npm

Argument of type 'JSONProperty' is not assignable to parameter of type 'Property'.
<a v-if="type.startsWith('#')" class="d-flex fw-bold type-box rounded fs-7 px-2 py-1" :href="type" @click.stop>
<span class="ref-type">{{ className(type) }}</span><eye-outline />
</a>
<span v-else class="type-box rounded fs-7 px-2 py-1">
{{ type }}
</span>
</template>
<component :is="collapsed ? ChevronDown : ChevronUp" class="arrow" />
</span>
</span>
</template>
<template #content>
<PropertyDetail :show-dynamic="showDynamic" :is-dynamic="showDynamic && isDynamic(property)" :property="property">
<template #markdown="{content}">
<slot :content="content" name="markdown" />
</template>
</PropertyDetail>
</template>
</Collapsible>
</div>
</template>
</Collapsible>
</template>

<script setup lang="ts">
import {extractTypeInfo, className} from "../../utils/schemaUtils";
import ChevronDown from "vue-material-design-icons/ChevronDown.vue";
import Collapsible from "../misc/Collapsible.vue";
import Tooltip from "../misc/Tooltip.vue";
import PropertyDetail from "./PropertyDetail.vue";
import ChevronUp from "vue-material-design-icons/ChevronUp.vue";
import Alert from "vue-material-design-icons/Alert.vue";
import Cancel from "vue-material-design-icons/Cancel.vue";
import AlphaBBox from "vue-material-design-icons/AlphaBBox.vue";
import type {JSONProperty} from "./PropertyType.vue";
import type {JSONSchema} from "./SchemaToHtml.vue";
import EyeOutline from "vue-material-design-icons/EyeOutline.vue";
import {ref, watch} from "vue";
withDefaults(defineProps<{ href?: string, sectionName: string, properties: [JSONProperty], showDynamic: boolean }>(), {
href: Math.random().toString(36).substring(2, 5),
showDynamic: true
});
const emit = defineEmits(["expand"]);
const initiallyExpanded = ref(false);
watch(
initiallyExpanded,
newInitiallyExpanded => {
if (newInitiallyExpanded) {
emit("expand");
}
}
);
const isDynamic = (property: JSONProperty): boolean => {
if (property["$dynamic"] === true) {
return true;
}
if (property["$dynamic"] === false) {
return false;
}
return property.oneOf?.some(prop => prop["$dynamic"] === true) ?? false;
};
function sortSchemaByRequired<T extends NonNullable<NonNullable<JSONSchema["properties"]>["properties"]>>(schema: T): T {
const requiredKeys = [];
const nonRequiredKeys = [];
for (const key in schema) {
if (typeof schema[key] === "object") {
if (schema[key].$required) {
requiredKeys.push(key);
} else {
nonRequiredKeys.push(key);
}
}
}
const sortedKeys = [...requiredKeys.sort(), ...nonRequiredKeys.sort()];
const sortedSchema: T = {} as T;
sortedKeys.forEach(key => {
sortedSchema[key] = schema[key];
});
return sortedSchema;
}
</script>

<style lang="scss" scoped>
@use "../../scss/variables" as variables;
.type-box, :deep(.type-box) {
border: 1px solid variables.$blue !important;
background: none;
.ref-type {
padding-right: 0.625rem;
+ * {
margin-left: 0.625rem;
}
}
}
.property:not(:first-child) {
border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color);
}
</style>
Loading

2 comments on commit 16feca3

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.