mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-19 18:05:41 -05:00
feat(blueprints): impl templated flow blueprints
# Conflicts: # core/src/main/java/io/kestra/core/serializers/YamlParser.java
This commit is contained in:
@@ -8,6 +8,7 @@ import io.micronaut.core.annotation.Nullable;
|
|||||||
import io.pebbletemplates.pebble.PebbleEngine;
|
import io.pebbletemplates.pebble.PebbleEngine;
|
||||||
import io.pebbletemplates.pebble.extension.Extension;
|
import io.pebbletemplates.pebble.extension.Extension;
|
||||||
import io.pebbletemplates.pebble.extension.Function;
|
import io.pebbletemplates.pebble.extension.Function;
|
||||||
|
import io.pebbletemplates.pebble.lexer.Syntax;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Singleton;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
@@ -37,6 +38,13 @@ public class PebbleEngineFactory {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PebbleEngine createWithCustomSyntax(Syntax syntax, Class<? extends Extension> extension) {
|
||||||
|
PebbleEngine.Builder builder = newPebbleEngineBuilder()
|
||||||
|
.syntax(syntax);
|
||||||
|
this.applicationContext.getBeansOfType(extension).forEach(builder::extension);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
public PebbleEngine createWithMaskedFunctions(VariableRenderer renderer, final List<String> functionsToMask) {
|
public PebbleEngine createWithMaskedFunctions(VariableRenderer renderer, final List<String> functionsToMask) {
|
||||||
|
|
||||||
PebbleEngine.Builder builder = newPebbleEngineBuilder();
|
PebbleEngine.Builder builder = newPebbleEngineBuilder();
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ public final class YamlParser {
|
|||||||
return read(input, cls, type(cls));
|
return read(input, cls, type(cls));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T parse(String input, Class<T> cls, Boolean strict) {
|
||||||
|
return strict ? read(input, cls, type(cls)) : readNonStrict(input, cls, type(cls));
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> T parse(Map<String, Object> input, Class<T> cls, Boolean strict) {
|
public static <T> T parse(Map<String, Object> input, Class<T> cls, Boolean strict) {
|
||||||
ObjectMapper currentMapper = strict ? STRICT_MAPPER : NON_STRICT_MAPPER;
|
ObjectMapper currentMapper = strict ? STRICT_MAPPER : NON_STRICT_MAPPER;
|
||||||
|
|
||||||
@@ -81,6 +85,13 @@ public final class YamlParser {
|
|||||||
throw toConstraintViolationException(input, resource, e);
|
throw toConstraintViolationException(input, resource, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static <T> T readNonStrict(String input, Class<T> objectClass, String resource) {
|
||||||
|
try {
|
||||||
|
return NON_STRICT_MAPPER.readValue(input, objectClass);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw toConstraintViolationException(input, resource, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
private static String formatYamlErrorMessage(String originalMessage, JsonProcessingException e) {
|
private static String formatYamlErrorMessage(String originalMessage, JsonProcessingException e) {
|
||||||
StringBuilder friendlyMessage = new StringBuilder();
|
StringBuilder friendlyMessage = new StringBuilder();
|
||||||
if (originalMessage.contains("Expected a field name")) {
|
if (originalMessage.contains("Expected a field name")) {
|
||||||
|
|||||||
46
ui/package-lock.json
generated
46
ui/package-lock.json
generated
@@ -4220,18 +4220,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shikijs/langs": {
|
"node_modules/@shikijs/langs": {
|
||||||
"version": "3.19.0",
|
"version": "3.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.20.0.tgz",
|
||||||
"integrity": "sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg==",
|
"integrity": "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@shikijs/types": "3.19.0"
|
"@shikijs/types": "3.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shikijs/langs/node_modules/@shikijs/types": {
|
"node_modules/@shikijs/langs/node_modules/@shikijs/types": {
|
||||||
"version": "3.19.0",
|
"version": "3.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz",
|
||||||
"integrity": "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ==",
|
"integrity": "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@shikijs/vscode-textmate": "^10.0.2",
|
"@shikijs/vscode-textmate": "^10.0.2",
|
||||||
@@ -4258,18 +4258,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shikijs/themes": {
|
"node_modules/@shikijs/themes": {
|
||||||
"version": "3.19.0",
|
"version": "3.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.20.0.tgz",
|
||||||
"integrity": "sha512-H36qw+oh91Y0s6OlFfdSuQ0Ld+5CgB/VE6gNPK+Hk4VRbVG/XQgkjnt4KzfnnoO6tZPtKJKHPjwebOCfjd6F8A==",
|
"integrity": "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@shikijs/types": "3.19.0"
|
"@shikijs/types": "3.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shikijs/themes/node_modules/@shikijs/types": {
|
"node_modules/@shikijs/themes/node_modules/@shikijs/types": {
|
||||||
"version": "3.19.0",
|
"version": "3.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz",
|
||||||
"integrity": "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ==",
|
"integrity": "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@shikijs/vscode-textmate": "^10.0.2",
|
"@shikijs/vscode-textmate": "^10.0.2",
|
||||||
@@ -18914,24 +18914,6 @@
|
|||||||
"hast-util-to-html": "^9.0.5"
|
"hast-util-to-html": "^9.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/shiki/node_modules/@shikijs/langs": {
|
|
||||||
"version": "3.20.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.20.0.tgz",
|
|
||||||
"integrity": "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@shikijs/types": "3.20.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shiki/node_modules/@shikijs/themes": {
|
|
||||||
"version": "3.20.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.20.0.tgz",
|
|
||||||
"integrity": "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@shikijs/types": "3.20.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shiki/node_modules/@shikijs/types": {
|
"node_modules/shiki/node_modules/@shikijs/types": {
|
||||||
"version": "3.20.0",
|
"version": "3.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
import {ref, computed, watch, onMounted, nextTick, useAttrs} from "vue";
|
import {ref, computed, watch, onMounted, nextTick, useAttrs} from "vue";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import EnterpriseBadge from "./EnterpriseBadge.vue";
|
import EnterpriseBadge from "./EnterpriseBadge.vue";
|
||||||
import BlueprintDetail from "./flows/blueprints/BlueprintDetail.vue";
|
import BlueprintDetail from "../override/components/flows/blueprints/BlueprintDetail.vue";
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|||||||
@@ -37,25 +37,31 @@
|
|||||||
const setupFlow = async () => {
|
const setupFlow = async () => {
|
||||||
const blueprintId = route.query.blueprintId as string;
|
const blueprintId = route.query.blueprintId as string;
|
||||||
const blueprintSource = route.query.blueprintSource as BlueprintType;
|
const blueprintSource = route.query.blueprintSource as BlueprintType;
|
||||||
|
const blueprintSourceYaml = route.query.blueprintSourceYaml as string;
|
||||||
const implicitDefaultNamespace = authStore.user.getNamespacesForAction(
|
const implicitDefaultNamespace = authStore.user.getNamespacesForAction(
|
||||||
permission.FLOW,
|
permission.FLOW,
|
||||||
action.CREATE,
|
action.CREATE,
|
||||||
)[0];
|
)[0];
|
||||||
let flowYaml = "";
|
let flowYaml = "";
|
||||||
const id = getRandomID();
|
const id = getRandomID();
|
||||||
const selectedNamespace = (route.query.namespace as string)
|
const selectedNamespace = (route.query.namespace as string)
|
||||||
?? defaultNamespace()
|
?? defaultNamespace()
|
||||||
?? implicitDefaultNamespace
|
?? implicitDefaultNamespace
|
||||||
?? "company.team";
|
?? "company.team";
|
||||||
|
|
||||||
if (route.query.copy && flowStore.flow) {
|
if (route.query.copy && flowStore.flow) {
|
||||||
flowYaml = flowStore.flow.source;
|
flowYaml = flowStore.flow.source;
|
||||||
} else if (blueprintId && blueprintSource) {
|
} else if (blueprintId && blueprintSourceYaml) {
|
||||||
|
flowYaml = blueprintSourceYaml;
|
||||||
|
} else if(blueprintId && blueprintSource === "community"){
|
||||||
flowYaml = await blueprintsStore.getBlueprintSource({
|
flowYaml = await blueprintsStore.getBlueprintSource({
|
||||||
type: blueprintSource,
|
type: blueprintSource,
|
||||||
kind: "flow",
|
kind: "flow",
|
||||||
id: blueprintId
|
id: blueprintId
|
||||||
});
|
});
|
||||||
|
} else if (blueprintId) {
|
||||||
|
const flowBlueprint = await blueprintsStore.getFlowBlueprint(blueprintId);
|
||||||
|
flowYaml = flowBlueprint.source;
|
||||||
} else {
|
} else {
|
||||||
flowYaml = `
|
flowYaml = `
|
||||||
id: ${id}
|
id: ${id}
|
||||||
|
|||||||
@@ -263,7 +263,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import ValidationError from "../flows/ValidationError.vue";
|
import ValidationError from "../flows/ValidationError.vue";
|
||||||
import {toRaw} from "vue";
|
import {markRaw, toRaw} from "vue";
|
||||||
import {mapStores} from "pinia";
|
import {mapStores} from "pinia";
|
||||||
import {useExecutionsStore} from "../../stores/executions";
|
import {useExecutionsStore} from "../../stores/executions";
|
||||||
import debounce from "lodash/debounce";
|
import debounce from "lodash/debounce";
|
||||||
@@ -336,10 +336,10 @@
|
|||||||
editingArrayId: null,
|
editingArrayId: null,
|
||||||
editableItems: {},
|
editableItems: {},
|
||||||
// expose icon components to the template so linters and the template can resolve them
|
// expose icon components to the template so linters and the template can resolve them
|
||||||
DeleteOutline,
|
DeleteOutline: markRaw(DeleteOutline),
|
||||||
Pencil,
|
Pencil:markRaw(Pencil),
|
||||||
Plus,
|
Plus:markRaw(Plus),
|
||||||
ContentSave
|
ContentSave:markRaw(ContentSave)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue", "update:modelValueNoDefault", "update:checks", "confirm", "validation"],
|
emits: ["update:modelValue", "update:modelValueNoDefault", "update:checks", "confirm", "validation"],
|
||||||
@@ -566,6 +566,7 @@
|
|||||||
} else {
|
} else {
|
||||||
this.$emit("validation", {
|
this.$emit("validation", {
|
||||||
formData: formData,
|
formData: formData,
|
||||||
|
inputsMetaData: this.inputsMetaData,
|
||||||
callback: (response) => {
|
callback: (response) => {
|
||||||
metadataCallback(response);
|
metadataCallback(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,16 +90,16 @@
|
|||||||
|
|
||||||
import ChevronLeft from "vue-material-design-icons/ChevronLeft.vue";
|
import ChevronLeft from "vue-material-design-icons/ChevronLeft.vue";
|
||||||
|
|
||||||
import Editor from "../../inputs/Editor.vue";
|
import Editor from "../../../../components/inputs/Editor.vue";
|
||||||
import Markdown from "../../layout/Markdown.vue";
|
import Markdown from "../../../../components/layout/Markdown.vue";
|
||||||
import TopNavBar from "../../layout/TopNavBar.vue";
|
import TopNavBar from "../../../../components/layout/TopNavBar.vue";
|
||||||
import LowCodeEditor from "../../inputs/LowCodeEditor.vue";
|
import LowCodeEditor from "../../../../components/inputs/LowCodeEditor.vue";
|
||||||
import CopyToClipboard from "../../layout/CopyToClipboard.vue";
|
import CopyToClipboard from "../../../../components/layout/CopyToClipboard.vue";
|
||||||
import TaskIcon from "@kestra-io/ui-libs/src/components/misc/TaskIcon.vue";
|
import TaskIcon from "@kestra-io/ui-libs/src/components/misc/TaskIcon.vue";
|
||||||
|
|
||||||
import {useFlowStore} from "../../../stores/flow";
|
import {useFlowStore} from "../../../../stores/flow";
|
||||||
import {usePluginsStore} from "../../../stores/plugins";
|
import {usePluginsStore} from "../../../../stores/plugins";
|
||||||
import {useBlueprintsStore} from "../../../stores/blueprints";
|
import {useBlueprintsStore} from "../../../../stores/blueprints";
|
||||||
|
|
||||||
import {canCreate} from "override/composables/blueprintsPermissions";
|
import {canCreate} from "override/composables/blueprintsPermissions";
|
||||||
import {parse as parseFlow} from "@kestra-io/ui-libs/flow-yaml-utils";
|
import {parse as parseFlow} from "@kestra-io/ui-libs/flow-yaml-utils";
|
||||||
@@ -170,8 +170,8 @@
|
|||||||
} else if (props.kind === "dashboard") {
|
} else if (props.kind === "dashboard") {
|
||||||
additionalQuery = {
|
additionalQuery = {
|
||||||
name: "home",
|
name: "home",
|
||||||
params: route.params?.tenant === undefined
|
params: route.params?.tenant === undefined
|
||||||
? undefined
|
? undefined
|
||||||
: JSON.stringify({tenant: route.params.tenant}),
|
: JSON.stringify({tenant: route.params.tenant}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -35,9 +35,8 @@
|
|||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import TopNavBar from "../../../../components/layout/TopNavBar.vue";
|
import TopNavBar from "../../../../components/layout/TopNavBar.vue";
|
||||||
import DottedLayout from "../../../../components/layout/DottedLayout.vue";
|
import DottedLayout from "../../../../components/layout/DottedLayout.vue";
|
||||||
// @ts-expect-error - Component not typed
|
import BlueprintDetail from "../../../../override/components/flows/blueprints/BlueprintDetail.vue";
|
||||||
import BlueprintDetail from "../../../../components/flows/blueprints/BlueprintDetail.vue";
|
import BlueprintsBrowser from "../../../../override/components/flows/blueprints/BlueprintsBrowser.vue";
|
||||||
import BlueprintsBrowser from "./BlueprintsBrowser.vue";
|
|
||||||
import DemoBlueprints from "../../../../components/demo/Blueprints.vue";
|
import DemoBlueprints from "../../../../components/demo/Blueprints.vue";
|
||||||
import useRouteContext from "../../../../composables/useRouteContext";
|
import useRouteContext from "../../../../composables/useRouteContext";
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="action-button">
|
<div class="action-button">
|
||||||
<slot name="buttons" :blueprint="blueprint" />
|
|
||||||
<el-tooltip v-if="embed && !system" trigger="click" content="Copied" placement="left" :autoClose="2000" effect="light">
|
<el-tooltip v-if="embed && !system" trigger="click" content="Copied" placement="left" :autoClose="2000" effect="light">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -77,9 +76,11 @@
|
|||||||
class="p-2"
|
class="p-2"
|
||||||
/>
|
/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-button v-else-if="userCanCreate" type="primary" size="default" @click.prevent.stop="blueprintToEditor(blueprint.id)">
|
<slot name="buttons" :blueprint="{...blueprint, kind: props.blueprintKind, type: props.blueprintType}">
|
||||||
{{ $t('use') }}
|
<el-button v-if="!embed && userCanCreate" type="primary" size="default" @click.prevent.stop="blueprintToEditor(blueprint.id)">
|
||||||
</el-button>
|
{{ $t('use') }}
|
||||||
|
</el-button>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default [
|
|||||||
}
|
}
|
||||||
if(change) {
|
if(change) {
|
||||||
next({
|
next({
|
||||||
...to,
|
...to,
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -79,7 +79,7 @@ export default [
|
|||||||
|
|
||||||
//Blueprints
|
//Blueprints
|
||||||
{name: "blueprints", path: "/:tenant?/blueprints/:kind/:tab", component: () => import("override/components/flows/blueprints/Blueprints.vue"), props: true},
|
{name: "blueprints", path: "/:tenant?/blueprints/:kind/:tab", component: () => import("override/components/flows/blueprints/Blueprints.vue"), props: true},
|
||||||
{name: "blueprints/view", path: "/:tenant?/blueprints/:kind/:tab/:blueprintId", component: () => import("../components/flows/blueprints/BlueprintDetail.vue"), props: true},
|
{name: "blueprints/view", path: "/:tenant?/blueprints/:kind/:tab/:blueprintId", component: () => import("../override/components/flows/blueprints/BlueprintDetail.vue"), props: true},
|
||||||
|
|
||||||
//Documentation
|
//Documentation
|
||||||
{name: "plugins/list", path: "/:tenant?/plugins", component: () => import("../components/plugins/Plugin.vue")},
|
{name: "plugins/list", path: "/:tenant?/plugins", component: () => import("../components/plugins/Plugin.vue")},
|
||||||
|
|||||||
@@ -24,6 +24,31 @@ interface Blueprint {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TemplateArgument {
|
||||||
|
id: string,
|
||||||
|
displayName: string,
|
||||||
|
type: string,
|
||||||
|
itemType?: string,
|
||||||
|
required: boolean,
|
||||||
|
defaults?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlueprintTemplate {
|
||||||
|
source: string;
|
||||||
|
templateArguments: Record<string, TemplateArgument>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowBlueprint {
|
||||||
|
id: string,
|
||||||
|
title: string,
|
||||||
|
description: string,
|
||||||
|
includedTasks?: string[],
|
||||||
|
tags?: string[],
|
||||||
|
source: string,
|
||||||
|
publishedAt?: string,
|
||||||
|
template?: BlueprintTemplate
|
||||||
|
}
|
||||||
|
|
||||||
const API_URL = "https://api.kestra.io/v1";
|
const API_URL = "https://api.kestra.io/v1";
|
||||||
const VALIDATE = {validateStatus: (status: number) => status === 200 || status === 401};
|
const VALIDATE = {validateStatus: (status: number) => status === 200 || status === 401};
|
||||||
|
|
||||||
@@ -95,6 +120,54 @@ export const useBlueprintsStore = defineStore("blueprints", () => {
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFlowBlueprint = async (id: string): Promise<FlowBlueprint> => {
|
||||||
|
const url = `${apiUrl()}/blueprints/flow/${id}`;
|
||||||
|
|
||||||
|
const response = await axios.get(url);
|
||||||
|
|
||||||
|
if (response.data?.id) {
|
||||||
|
trackBlueprintSelection(response.data.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
blueprint.value = response.data;
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createFlowBlueprint = async (toCreate: {source: string, title: string, description: string, tags: string[]}): Promise<FlowBlueprint> => {
|
||||||
|
const url = `${apiUrl()}/blueprints/flows`;
|
||||||
|
const body = {
|
||||||
|
...toCreate
|
||||||
|
}
|
||||||
|
const response = await axios.post(url, body);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateFlowBlueprint = async (id: string, toUpdate: {source: string, title: string, description: string, tags: string[]}) :Promise<FlowBlueprint> => {
|
||||||
|
const url = `${apiUrl()}/blueprints/flows/${id}`;
|
||||||
|
const body = {
|
||||||
|
...toUpdate
|
||||||
|
}
|
||||||
|
const response = await axios.put(url, body);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteFlowBlueprint = async (idToDelete: string) => {
|
||||||
|
const url = `${apiUrl()}/blueprints/flows/${idToDelete}`;
|
||||||
|
await axios.delete(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useFlowBlueprintTemplate = async (id: string, inputs: Record<string, object>): Promise<{generatedFlowSource: string}> => {
|
||||||
|
const url = `${apiUrl()}/blueprints/flows/${id}/use-template`;
|
||||||
|
const body = {
|
||||||
|
templateArgumentsInputs: inputs
|
||||||
|
}
|
||||||
|
const response = await axios.post(url, body);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
blueprint,
|
blueprint,
|
||||||
blueprints,
|
blueprints,
|
||||||
@@ -106,5 +179,10 @@ export const useBlueprintsStore = defineStore("blueprints", () => {
|
|||||||
getBlueprintSource,
|
getBlueprintSource,
|
||||||
getBlueprintGraph,
|
getBlueprintGraph,
|
||||||
getBlueprintTags,
|
getBlueprintTags,
|
||||||
|
useFlowBlueprintTemplate,
|
||||||
|
getFlowBlueprint,
|
||||||
|
createFlowBlueprint,
|
||||||
|
updateFlowBlueprint,
|
||||||
|
deleteFlowBlueprint,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user