Compare commits

...

1 Commits

Author SHA1 Message Date
Bart Ledoux
27c35a9be9 refactor: update types 2025-12-19 10:42:30 +01:00
31 changed files with 73 additions and 82 deletions

6
ui/package-lock.json generated
View File

@@ -19216,9 +19216,9 @@
"license": "MIT"
},
"node_modules/storybook": {
"version": "9.1.16",
"resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.16.tgz",
"integrity": "sha512-339U14K6l46EFyRvaPS2ZlL7v7Pb+LlcXT8KAETrGPxq8v1sAjj2HAOB6zrlAK3M+0+ricssfAwsLCwt7Eg8TQ==",
"version": "9.1.17",
"resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.17.tgz",
"integrity": "sha512-kfr6kxQAjA96ADlH6FMALJwJ+eM80UqXy106yVHNgdsAP/CdzkkicglRAhZAvUycXK9AeadF6KZ00CWLtVMN4w==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -98,7 +98,6 @@
});
const panelWidth = ref(640)
const panelWrapper = ref<HTMLDivElement | null>(null)
const {startResizing, resizing} = useResizablePanel(activeTab)

View File

@@ -380,7 +380,6 @@
import TopNavBar from "../layout/TopNavBar.vue";
import BulkSelect from "../layout/BulkSelect.vue";
import LogsWrapper from "../logs/LogsWrapper.vue";
//@ts-expect-error No declaration file
import SelectTable from "../layout/SelectTable.vue";
import TriggerAvatar from "../flows/TriggerAvatar.vue";
import KSFilter from "../filter/components/KSFilter.vue";

View File

@@ -200,7 +200,6 @@
const activeStep = ref(0)
const userForm: Ref<any> = ref(null)
const surveyForm: Ref<any> = ref(null)
const userFormData = ref<UserFormData>({
firstName: "",

View File

@@ -113,10 +113,10 @@
provide(FULL_SOURCE_INJECTION_KEY, computed(() => dashboardStore.sourceCode ?? ""));
provide(POSITION_INJECTION_KEY, props.position ?? "after");
provide(ON_TASK_EDITOR_CLICK_INJECTION_KEY, (elt) => {
const type = elt?.type;
const cls = elt?.type;
dashboardStore.loadChart(elt);
if(type){
pluginsStore.updateDocumentation({type});
if(cls){
pluginsStore.updateDocumentation({cls});
}else{
pluginsStore.updateDocumentation();
}

View File

@@ -16,7 +16,6 @@
import {useExecutionsStore} from "../../stores/executions";
import {useExecutionRoot} from "./composables/useExecutionRoot";
import useRouteContext from "../../composables/useRouteContext";
//@ts-expect-error no declaration file
import Tabs from "../../components/Tabs.vue";
//@ts-expect-error no declaration file
import ExecutionRootTopBar from "./ExecutionRootTopBar.vue";

View File

@@ -24,11 +24,12 @@
import ChartAreaspline from "vue-material-design-icons/ChartAreaspline.vue"
import Drawer from "../Drawer.vue"
import MetricsTable from "./MetricsTable.vue"
import {Execution} from "../../stores/executions";
const props = defineProps<{
embed?: boolean;
taskRun: Record<string, any>;
execution: Record<string, any>;
execution: Execution;
}>();
const isOpen = ref(false)

View File

@@ -3,7 +3,7 @@
<el-button
type="primary"
tag="a"
:href="itemUrl(value.toString())"
:href="value && itemUrl(value.toString())"
target="_blank"
size="small"
:icon="Download"
@@ -11,7 +11,7 @@
>
{{ $t('download') }}
</el-button>
<FilePreview v-if="isFile(value)" :value="value.toString()" :executionId="execution.id" />
<FilePreview v-if="isFile(value)" :value="value.toString()" :executionId="execution?.id" />
<el-button disabled size="small" type="primary" v-if="humanSize">
({{ humanSize }})
</el-button>

View File

@@ -66,7 +66,6 @@
import {useRoute} from "vue-router";
// @ts-expect-error types to be done
import DateRange from "../../layout/DateRange.vue";
// @ts-expect-error types to be done
import TimeSelect from "./TimeSelect.vue";
import moment from "moment";

View File

@@ -23,7 +23,7 @@
import ClockOutline from "vue-material-design-icons/ClockOutline.vue";
interface Option {
value: string;
value?: string;
label: string;
}

View File

@@ -429,7 +429,7 @@
elements: execution.value?.trigger,
includeDebug: "trigger",
},
];
] as const;
const options = useValues("executions").VALUES.RELATIVE_DATE;
const timerange = ref<string>("PT168H"); // Default to last 7 days

View File

@@ -300,7 +300,6 @@
import TriggerAvatar from "./TriggerAvatar.vue";
import DataTable from "../layout/DataTable.vue";
import BulkSelect from "../layout/BulkSelect.vue";
//@ts-expect-error no declaration file
import SelectTable from "../layout/SelectTable.vue";
import KSFilter from "../filter/components/KSFilter.vue";
import MarkdownTooltip from "../layout/MarkdownTooltip.vue";

View File

@@ -32,6 +32,7 @@
import {TaskIcon} from "@kestra-io/ui-libs";
import {useI18n} from "vue-i18n";
import {useToast} from "../../utils/toast";
import {Execution} from "../../stores/executions";
interface Flow {
namespace: string;
@@ -39,11 +40,6 @@
triggers?: Trigger[];
}
interface Execution {
id: string;
trigger?: Trigger;
}
interface Trigger {
id: string;
type: string;

View File

@@ -33,12 +33,13 @@
import VarValue from "../executions/VarValue.vue";
import Markdown from "../layout/Markdown.vue";
import Cron from "../layout/Cron.vue";
import {Execution} from "../../stores/executions";
const {t, te} = useI18n();
defineProps<{
data: Record<string, any>;
execution?: Record<string, any>;
execution?: Execution;
}>();
const emit = defineEmits<{ (e: "on-copy", event: any): void }>();

View File

@@ -6,6 +6,6 @@
import BookmarkLink from "./BookmarkLink.vue"
defineProps<{
pages: {label?:string, path:string}[]
pages: {label:string, path:string}[]
}>()
</script>

View File

@@ -4,22 +4,16 @@
</span>
</template>
<script>
<script lang="ts" setup>
import {computed} from "vue";
import Utils from "../../utils/utils";
import cronstrue from "cronstrue";
import "cronstrue/locales/fr";
const props = defineProps<{
cronExpression?: string
}>()
export default {
props: {
cronExpression: {
type: String,
default: undefined
}
},
computed: {
humanReadableCron() {
return cronstrue.toString(this.cronExpression, {locale: Utils.getLang()});
}
}
}
const humanReadableCron = computed(() => {
return props.cronExpression ? cronstrue.toString(props.cronExpression, {locale: Utils.getLang()}) : "";
});
</script>

View File

@@ -4,31 +4,30 @@
</div>
</template>
<script>
import {mapStores} from "pinia";
<script setup lang="ts">
import {computed} from "vue";
import {cssVariable} from "@kestra-io/ui-libs";
import {useLayoutStore} from "../../stores/layout";
import {useMiscStore} from "override/stores/misc";
export default {
computed: {
...mapStores(useLayoutStore, useMiscStore),
name() {
return this.layoutStore.envName || this.miscStore.configs?.environment?.name;
},
color() {
if (this.layoutStore.envColor) {
return this.layoutStore.envColor;
}
const layoutStore = useLayoutStore();
const miscStore = useMiscStore();
if (this.miscStore.configs?.environment?.color) {
return this.miscStore.configs.environment.color;
}
const name = computed(() => {
return layoutStore.envName || miscStore.configs?.environment?.name;
});
return cssVariable("--bs-info");
}
const color = computed(() => {
if (layoutStore.envColor) {
return layoutStore.envColor;
}
}
if (miscStore.configs?.environment?.color) {
return miscStore.configs.environment.color;
}
return cssVariable("--bs-info");
});
</script>
<style scoped lang="scss">

View File

@@ -43,7 +43,7 @@
const table = ref<any>(null);
const hasSelection = ref(false);
const container = ref<HTMLElement>(null);
const container = ref<HTMLElement>();
const toggleRowExpansion = (row: any, expand?: boolean) => {
table.value?.toggleRowExpansion(row, expand);

View File

@@ -68,21 +68,27 @@
function disabledCurrentRoute(items: MenuItem[]) {
return items
.map(r => {
const newR = r as MenuItem & {class:string};
const routeName = $route.name?.toString();
if (r.href?.path === $route.path) {
r.disabled = true;
}
// route hack is still needed for blueprints
if (r.href !== "/" && ($route.path.startsWith(r.href) || r.routes?.includes($route.name))) {
r.class = "vsm--link_active";
if (r.href?.path && r.href.path !== "/" && ($route.path.startsWith(r.href.path)
|| routeName && r.routes?.includes(routeName))) {
newR.class = "vsm--link_active";
}
if (r.child && r.child.some(c => $route.path.startsWith(c.href) || c.routes?.includes($route.name))) {
r.class = "vsm--link_active";
r.child = disabledCurrentRoute(r.child);
if (r.child && r.child.some(c => c.href?.path && $route.path.startsWith(c.href.path)
|| routeName && c.routes?.includes(routeName))) {
newR.class = "vsm--link_active";
newR.child = disabledCurrentRoute(r.child);
}
return r;
return newR;
})
}

View File

@@ -165,7 +165,7 @@
// when tab is opened, load the documentation
onActivated(() => {
if(selectedTaskType.value && parentPath !== "inputs"){
pluginsStore.updateDocumentation({type: selectedTaskType.value, ...taskModel.value});
pluginsStore.updateDocumentation({cls: selectedTaskType.value, ...taskModel.value});
}
});

View File

@@ -67,7 +67,7 @@
</template>
<script setup lang="ts">
import {computed, ref, useTemplateRef, watch} from "vue";
import {computed, ref, watch} from "vue";
import {useI18n} from "vue-i18n";
import {DeleteOutline} from "../../utils/icons";
@@ -85,8 +85,6 @@
inheritAttrs: false,
});
const valueComponent = useTemplateRef<any[]>("valueComponent");
const props = withDefaults(defineProps<{
modelValue?: Record<string, any>;
schema?: any;

View File

@@ -13,7 +13,7 @@
:name="plugin.group"
:title="plugin.title?.capitalize()"
:key="plugin.group"
:ref="(el) => pluginRefs[plugin.group] = el"
:ref="(el: any) => pluginRefs[plugin.group] = el"
>
<ul class="toc-h3">
<li v-for="(types, namespace) in group(plugin)" :key="namespace">
@@ -70,7 +70,7 @@
const route = useRoute();
const pluginsStore = usePluginsStore();
const pluginRefs = reactive({});
const pluginRefs = reactive<Record<string, any>>({});
const activeNames = ref<string[]>([]);
const searchInput = ref<string>("");

View File

@@ -101,7 +101,7 @@
});
const addSecretModalVisible = ref(false);
const hasData = ref(undefined);
const hasData = ref<boolean | undefined>(undefined);
const {t} = useI18n({useScope: "global"});
const routeInfo = computed(() => ({title: t("secret.names")}));

View File

@@ -304,7 +304,6 @@
const form = ref<FormInstance>();
const dataTable = useTemplateRef<DataTableRef>("dataTable");
const selectTable = ref<InstanceType<typeof SelectTable>>();
const total = ref(0);
const hasData = ref<boolean>();

View File

@@ -195,7 +195,7 @@
return result;
});
const namespaceLabel = (path) => {
const namespaceLabel = (path: string) => {
const segments = path.split(".");
return segments.length > 1 ? segments[segments.length - 1] : path;
};

View File

@@ -20,6 +20,8 @@ import ShieldKeyOutline from "vue-material-design-icons/ShieldKeyOutline.vue";
import FlaskOutline from "vue-material-design-icons/FlaskOutline.vue";
export type MenuItem = {
title: string,
routes?: string[],
href?: {
path?: string,
name: string,
@@ -47,7 +49,8 @@ export function useLeftMenu() {
.filter(
(r) => typeof r.name === "string" && r.name.startsWith(route),
)
.map((r) => r.name);
.map((r) => r.name)
.filter((name) => typeof name === "string");
}
const flatMenuItems = (items: MenuItem[]): MenuItem[] => {

View File

@@ -1,5 +1,4 @@
import {ComputedRef} from "vue";
import type {JSONSchema} from "@kestra-io/ui-libs";
import {YamlElement} from "@kestra-io/ui-libs";
import * as YAML_UTILS from "@kestra-io/ui-libs/flow-yaml-utils";
import {QUOTE, YamlAutoCompletion} from "../../services/autoCompletionProvider";
@@ -109,7 +108,7 @@ export class FlowAutoCompletion extends YamlAutoCompletion {
const fetchTriggerVarsByType = await Promise.all(
distinct(flowAsJs?.triggers?.map(trigger => trigger.type))
.map(async triggerType => {
const triggerDoc: {schema: JSONSchema} | undefined = await this.pluginsStore.load({
const triggerDoc = await this.pluginsStore.load({
cls: triggerType,
commit: false
});

View File

@@ -5,7 +5,7 @@ const LOCAL_STORAGE_KEY = "starred.bookmarks"
const initialPages = localStorage.getItem(LOCAL_STORAGE_KEY) ?? "[]"
interface Page {
path: string;
label?: string;
label: string;
}
interface State {
@@ -25,7 +25,7 @@ export const useBookmarksStore = defineStore("bookmarks", {
this.updateAll(pages)
}
},
remove(page: Page) {
remove(page: Pick<Page, "path">) {
const pages = this.pages
const index = pages.findIndex(p => p.path === page.path)
if (index > -1) {

View File

@@ -93,7 +93,7 @@ export async function render(markdown: string, options: RenderOptions = {}) {
}
function applyEnhancedRenderers(md: any) {
const defaultHeadingOpen = md.renderer.rules.heading_open?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, env: any, self: any) => self.renderToken(tokens, idx, options));
const defaultHeadingOpen = md.renderer.rules.heading_open?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, _env: any, self: any) => self.renderToken(tokens, idx, options));
md.renderer.rules.heading_open = (tokens: any, idx: number, options: any, env: any, self: any) => {
const token = tokens[idx];
const level = typeof token.tag === "string" && /^h\d$/i.test(token.tag) ? Number(token.tag.substring(1)) : null;
@@ -104,7 +104,7 @@ function applyEnhancedRenderers(md: any) {
return defaultHeadingOpen(tokens, idx, options, env, self);
};
const defaultTableOpen = md.renderer.rules.table_open?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, env: any, self: any) => self.renderToken(tokens, idx, options));
const defaultTableOpen = md.renderer.rules.table_open?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, _env: any, self: any) => self.renderToken(tokens, idx, options));
md.renderer.rules.table_open = (tokens: any, idx: number, options: any, env: any, self: any) => {
const token = tokens[idx];
token.attrSet("class", "doc-table");
@@ -112,7 +112,7 @@ function applyEnhancedRenderers(md: any) {
return defaultTableOpen(tokens, idx, options, env, self);
};
const defaultFence = md.renderer.rules.fence?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, env: any, self: any) => self.renderToken(tokens, idx, options));
const defaultFence = md.renderer.rules.fence?.bind(md.renderer.rules) ?? ((tokens: any, idx: number, options: any, _env: any, self: any) => self.renderToken(tokens, idx, options));
md.renderer.rules.fence = (tokens: any, idx: number, options: any, env: any, self: any) => {
const token = tokens[idx];

View File

@@ -60,7 +60,7 @@ const mockFilterKeys = {
description: "Filter by key-value pairs",
comparators: [Comparators.IN],
valueType: "details",
} as FilterKeyConfig,
} as unknown as FilterKeyConfig,
radio: {
key: "child",
label: "Child",

View File

@@ -71,6 +71,7 @@ const revisionSourceMock = fn((revision: number) => {
`{"revision": ${revision}, "content": "Content for revision ${revision}"}`
);
});
export const Default: Story = {
render: render.bind({}),
args: {
@@ -119,7 +120,7 @@ export const Default: Story = {
confirmButton.click();
});
await waitFor(() => expect(revisions[revisions.length - 1].revision).toEqual(5));
await expect(revisions[revisions.length - 1].source).toContain('"revision": 1');
await expect(revisions[revisions.length - 1].source ?? "").toContain("\"revision\": 1");
await expect(revisionSourceMock).not.toHaveBeenCalledWith(5);
}
};