Initial release
Change-Id: If51199c8e3e9655001b2ba0f4ef7d762029d5764
This commit is contained in:
parent
224075f69b
commit
21aa57a51b
@ -1,4 +1,4 @@
|
|||||||
FROM docker.io/library/node:20.11.0-bookworm
|
FROM docker.io/library/node:21.4.0-bookworm
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN corepack enable pnpm && pnpm install && npx vue-tsc
|
RUN corepack enable pnpm && pnpm install && npx vue-tsc
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
"name": "enigma-nebulous",
|
"name": "enigma-nebulous",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "v21.4.0"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vite",
|
"serve": "vite",
|
||||||
"build": "vue-tsc && vite build",
|
"build": "vue-tsc && vite build",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<div class="py-5 md:py-0">
|
<div class="py-5 md:py-0">
|
||||||
<MobileMenu v-if="!isMenuHidden" />
|
<MobileMenu v-if="!isMenuHidden" />
|
||||||
<Header v-if="!isMenuHidden" layout="side-menu" />
|
<Header v-if="!isMenuHidden" layout="side-menu" />
|
||||||
|
|
||||||
<div class="flex overflow-hidden">
|
<div class="flex overflow-hidden">
|
||||||
<SideMenu v-if="!isMenuHidden" />
|
<SideMenu v-if="!isMenuHidden" />
|
||||||
<!-- BEGIN: Content -->
|
<!-- BEGIN: Content -->
|
||||||
@ -30,6 +31,7 @@ import SideMenu from "@/components/SideMenu"
|
|||||||
import MobileMenu from "@/components/MobileMenu"
|
import MobileMenu from "@/components/MobileMenu"
|
||||||
import Modal from "@/components/Modal"
|
import Modal from "@/components/Modal"
|
||||||
import Snackbar from "@/components/Snackbar"
|
import Snackbar from "@/components/Snackbar"
|
||||||
|
import Footer from "@/base-components/Headless/Menu/Footer.vue";
|
||||||
|
|
||||||
const route: RouteLocationNormalizedLoaded = useRoute()
|
const route: RouteLocationNormalizedLoaded = useRoute()
|
||||||
|
|
||||||
@ -44,4 +46,6 @@ watch(
|
|||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -19,7 +19,7 @@ import ICodeEditor = editor.ICodeEditor
|
|||||||
|
|
||||||
interface IEditorProps {
|
interface IEditorProps {
|
||||||
modelValue: string
|
modelValue: string
|
||||||
language: "yaml" | "math"
|
language: "yaml" | "math" | "json" | "casbin"
|
||||||
theme?: string
|
theme?: string
|
||||||
fontSize?: number
|
fontSize?: number
|
||||||
destroyDelay?: number
|
destroyDelay?: number
|
||||||
|
@ -8,6 +8,7 @@ export const keywords = [
|
|||||||
"POW",
|
"POW",
|
||||||
"LOG",
|
"LOG",
|
||||||
"LOG10",
|
"LOG10",
|
||||||
|
"MEAN",
|
||||||
"LN2",
|
"LN2",
|
||||||
"LN10",
|
"LN10",
|
||||||
"LOG10E",
|
"LOG10E",
|
||||||
|
@ -17,7 +17,11 @@
|
|||||||
<div class="hidden md:flex w-full max-w-4xl mr-8">
|
<div class="hidden md:flex w-full max-w-4xl mr-8">
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
</div>
|
</div>
|
||||||
<Button variant="primary" class="ml-auto" @click="onSaveClick">Save</Button>
|
<div class="ml-auto" v-if="!saveEnabled">
|
||||||
|
</div>
|
||||||
|
<Button variant="primary" class="ml-auto" @click="onSaveClick"
|
||||||
|
v-if="saveEnabled"
|
||||||
|
>Save</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="currentStage.next"
|
v-if="currentStage.next"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@ -104,7 +108,9 @@
|
|||||||
<!-- BEGIN: CANCEL BUTTONS LINE -->
|
<!-- BEGIN: CANCEL BUTTONS LINE -->
|
||||||
<div class="pb-2 mt-auto">
|
<div class="pb-2 mt-auto">
|
||||||
<div class="flex justify-between items-end mt-5">
|
<div class="flex justify-between items-end mt-5">
|
||||||
<Button variant="outline-danger" class="ml-auto" @click="onExitClickHandler">Cancel</Button>
|
<Button variant="outline-danger" class="ml-auto" @click="onExitClickHandler">
|
||||||
|
{{saveEnabled ? 'Cancel' : 'Close'}}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END: CANCEL BUTTONS LINE -->
|
<!-- END: CANCEL BUTTONS LINE -->
|
||||||
@ -126,6 +132,7 @@ const router = useRouter()
|
|||||||
|
|
||||||
interface MultiStepsProviderProps {
|
interface MultiStepsProviderProps {
|
||||||
stages: Record<string, Stage>
|
stages: Record<string, Stage>
|
||||||
|
saveEnabled: boolean
|
||||||
entrypointComponent: string
|
entrypointComponent: string
|
||||||
returnRouteName: string
|
returnRouteName: string
|
||||||
responseErrorMessages: Array<string>
|
responseErrorMessages: Array<string>
|
||||||
@ -165,6 +172,7 @@ watch(currentStageName, () => {
|
|||||||
|
|
||||||
const clientErrorMessages = ref<Array<string>>([])
|
const clientErrorMessages = ref<Array<string>>([])
|
||||||
|
|
||||||
|
const saveEnabled = computed(() => props.saveEnabled)
|
||||||
const currentStage = computed<Stage>(() => props.stages[currentStageName.value])
|
const currentStage = computed<Stage>(() => props.stages[currentStageName.value])
|
||||||
const visibleStagesHeads = computed(() => Object.values(props.stages).filter(({ isInvisible }) => !isInvisible))
|
const visibleStagesHeads = computed(() => Object.values(props.stages).filter(({ isInvisible }) => !isInvisible))
|
||||||
const lastStageNumber = computed(() => Math.max(...Object.values(props.stages).map(({ stage }) => stage)))
|
const lastStageNumber = computed(() => Math.max(...Object.values(props.stages).map(({ stage }) => stage)))
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<option value="maximize">Maximize Utility</option>
|
<option value="maximize">Maximize Utility</option>
|
||||||
|
<option value="minimize">Minimize Utility</option>
|
||||||
<option value="constant">Constant</option>
|
<option value="constant">Constant</option>
|
||||||
</FormSelect>
|
</FormSelect>
|
||||||
<Lucide icon="Trash2" class="w-10 text-danger" @click="removeFunction(index)" />
|
<Lucide icon="Trash2" class="w-10 text-danger" @click="removeFunction(index)" />
|
||||||
|
@ -8,12 +8,14 @@
|
|||||||
<MetricsTemplateDesktop
|
<MetricsTemplateDesktop
|
||||||
:metrics="localMetrics"
|
:metrics="localMetrics"
|
||||||
:componentList="props.componentList"
|
:componentList="props.componentList"
|
||||||
|
:templateNames="props.templateNames"
|
||||||
@levelChangeHandler="onLevelChangeHandler"
|
@levelChangeHandler="onLevelChangeHandler"
|
||||||
class="hidden md:table"
|
class="hidden md:table"
|
||||||
/>
|
/>
|
||||||
<MetricsTemplateMobile
|
<MetricsTemplateMobile
|
||||||
:metrics="localMetrics"
|
:metrics="localMetrics"
|
||||||
:componentList="props.componentList"
|
:componentList="props.componentList"
|
||||||
|
:templateName="props.templateNames"
|
||||||
@levelChangeHandler="onLevelChangeHandler"
|
@levelChangeHandler="onLevelChangeHandler"
|
||||||
class="md:hidden"
|
class="md:hidden"
|
||||||
/>
|
/>
|
||||||
@ -21,37 +23,37 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue"
|
import {computed, ref} from "vue"
|
||||||
import Lucide from "@/base-components/Lucide/Lucide.vue"
|
import Lucide from "@/base-components/Lucide/Lucide.vue"
|
||||||
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
||||||
import MetricsTemplateDesktop from "@/components/Application/Metrics/MetricsTemplateDesktop.vue"
|
import MetricsTemplateDesktop from "@/components/Application/Metrics/MetricsTemplateDesktop.vue"
|
||||||
import MetricsTemplateMobile from "@/components/Application/Metrics/MetricsTemplateMobile.vue"
|
import MetricsTemplateMobile from "@/components/Application/Metrics/MetricsTemplateMobile.vue"
|
||||||
|
import {ITemplate} from "@/interfaces/template.interface.ts";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
interface MetricsProps {
|
interface MetricsProps {
|
||||||
componentList: Array<{ label: string; value: string }>
|
componentList: Array<{ label: string; value: string }>
|
||||||
metrics: Array<IMetricRaw | IMetricComposite>
|
metrics: Array<IMetricRaw | IMetricComposite>
|
||||||
|
templateNames: Array<string>
|
||||||
}
|
}
|
||||||
const props = defineProps<MetricsProps>()
|
const props = defineProps<MetricsProps>()
|
||||||
|
|
||||||
const localMetrics = computed(() => props.metrics)
|
const localMetrics = computed(() => props.metrics)
|
||||||
|
|
||||||
|
|
||||||
const addMetric = () => {
|
const addMetric = () => {
|
||||||
localMetrics.value.push({
|
localMetrics.value.push({
|
||||||
type: "raw",
|
type: "raw",
|
||||||
name: "",
|
name: "",
|
||||||
sensor: "",
|
sensor: "",
|
||||||
config: [],
|
config: [],
|
||||||
|
level:"global",
|
||||||
|
components:[],
|
||||||
isWindowOutputRaw: true,
|
isWindowOutputRaw: true,
|
||||||
isWindowInputRaw: true,
|
|
||||||
outputRaw: {
|
outputRaw: {
|
||||||
type: "all",
|
type: "all",
|
||||||
interval: 0,
|
interval: 0,
|
||||||
unit: "ms"
|
unit: "ms"
|
||||||
},
|
|
||||||
inputRaw: {
|
|
||||||
type: "all",
|
|
||||||
interval: 0,
|
|
||||||
unit: "ms"
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { computed, reactive, ref } from "vue"
|
import { computed } from 'vue';
|
||||||
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import { required } from "@vuelidate/validators"
|
import { required } from "@vuelidate/validators"
|
||||||
@ -8,30 +8,25 @@ export function useMetrics(metrics: Array<IMetricComposite | IMetricRaw>) {
|
|||||||
const localMetrics = computed(() => metrics)
|
const localMetrics = computed(() => metrics)
|
||||||
const previouslyEditedMetricsData: Record<number, IMetricComposite | IMetricRaw> = {}
|
const previouslyEditedMetricsData: Record<number, IMetricComposite | IMetricRaw> = {}
|
||||||
|
|
||||||
const metricsRawRules = {
|
|
||||||
|
const metricsRawRules = computed(() => ({
|
||||||
name: { required }
|
name: { required }
|
||||||
}
|
}));
|
||||||
|
|
||||||
const metricsCompositeRules = {
|
const metricsCompositeRules = computed(() => ({
|
||||||
name: { required },
|
name: { required },
|
||||||
formula: { required }
|
formula: { required }
|
||||||
}
|
}));
|
||||||
|
|
||||||
const metricRules = reactive({
|
const getValidationRules = (type:string) => {
|
||||||
name: { required },
|
if (type === 'composite') {
|
||||||
formula: { required }
|
return metricsCompositeRules.value;
|
||||||
})
|
} else if (type === 'raw') {
|
||||||
|
return metricsRawRules.value;
|
||||||
// Could not make it work better. Only "reactive" can keep validation rules dynamic
|
|
||||||
const getValidationRules = (type: string) => {
|
|
||||||
if (type === "composite") {
|
|
||||||
Object.assign(metricRules, { formula: { required } })
|
|
||||||
} else {
|
|
||||||
// @ts-ignore
|
|
||||||
delete metricRules.formula
|
|
||||||
}
|
}
|
||||||
return metricRules
|
return { name: { required } };
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const metricTypeChangeHandler = (index: number, event: HTMLElementEvent<HTMLSelectElement>) => {
|
const metricTypeChangeHandler = (index: number, event: HTMLElementEvent<HTMLSelectElement>) => {
|
||||||
const { target } = event
|
const { target } = event
|
||||||
@ -45,11 +40,13 @@ export function useMetrics(metrics: Array<IMetricComposite | IMetricRaw>) {
|
|||||||
type: "composite",
|
type: "composite",
|
||||||
name: "",
|
name: "",
|
||||||
formula: "",
|
formula: "",
|
||||||
|
template:"",
|
||||||
|
level:"global",
|
||||||
|
components:[],
|
||||||
isWindowInput: true,
|
isWindowInput: true,
|
||||||
isWindowOutput: true,
|
isWindowOutput: true,
|
||||||
level: "global",
|
|
||||||
input: {
|
input: {
|
||||||
type: "all",
|
type: "batch",
|
||||||
interval: 0,
|
interval: 0,
|
||||||
unit: "ms"
|
unit: "ms"
|
||||||
},
|
},
|
||||||
@ -63,17 +60,13 @@ export function useMetrics(metrics: Array<IMetricComposite | IMetricRaw>) {
|
|||||||
localMetrics.value[index] = {
|
localMetrics.value[index] = {
|
||||||
type: "raw",
|
type: "raw",
|
||||||
isWindowOutputRaw: true,
|
isWindowOutputRaw: true,
|
||||||
isWindowInputRaw: true,
|
level:"global",
|
||||||
|
components:[],
|
||||||
outputRaw: {
|
outputRaw: {
|
||||||
type: "all",
|
type: "all",
|
||||||
interval: 0,
|
interval: 0,
|
||||||
unit: "ms"
|
unit: "ms"
|
||||||
},
|
},
|
||||||
inputRaw: {
|
|
||||||
type: "all",
|
|
||||||
interval: 0,
|
|
||||||
unit: "ms"
|
|
||||||
},
|
|
||||||
name: "",
|
name: "",
|
||||||
sensor: "",
|
sensor: "",
|
||||||
config: []
|
config: []
|
||||||
|
@ -95,6 +95,19 @@
|
|||||||
<option value="components">Components</option>
|
<option value="components">Components</option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col flex-grow">
|
||||||
|
<Label>Template</Label>
|
||||||
|
<Select
|
||||||
|
v-model="metric.template"
|
||||||
|
:class="{
|
||||||
|
'input--invalid': v.template?.$error || hasBackendError(`metrics[${index}].template`)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<option v-for="(template, templateOptionIndex) in templateNames" :key="templateOptionIndex">
|
||||||
|
{{ template }}
|
||||||
|
</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="metric.level === 'components' && metric.components" class="flex flex-col">
|
<div v-if="metric.level === 'components' && metric.components" class="flex flex-col">
|
||||||
<Label>Components</Label>
|
<Label>Components</Label>
|
||||||
@ -118,6 +131,7 @@
|
|||||||
<template v-else> <option>No keys available</option> </template>
|
<template v-else> <option>No keys available</option> </template>
|
||||||
</TomSelect>
|
</TomSelect>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@ -139,7 +153,7 @@
|
|||||||
id="windowInput"
|
id="windowInput"
|
||||||
v-model="metric.isWindowInput"
|
v-model="metric.isWindowInput"
|
||||||
/>
|
/>
|
||||||
<FormCheck.Label class="font-bold" for="windowInput">Window Input</FormCheck.Label>
|
<FormCheck.Label class="font-bold" for="windowInput">Input Intervals</FormCheck.Label>
|
||||||
</FormCheck>
|
</FormCheck>
|
||||||
<div v-if="metric.isWindowInput && metric.input" class="flex space-x-3">
|
<div v-if="metric.isWindowInput && metric.input" class="flex space-x-3">
|
||||||
<div class="flex flex-col flex-grow">
|
<div class="flex flex-col flex-grow">
|
||||||
@ -149,7 +163,7 @@
|
|||||||
v-model="metric.input.type"
|
v-model="metric.input.type"
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.type`) }"
|
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.type`) }"
|
||||||
>
|
>
|
||||||
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS" :key="behaviorIndex">
|
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS_INPUT" :key="behaviorIndex">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
</Select>
|
</Select>
|
||||||
@ -184,7 +198,7 @@
|
|||||||
id="windowOutput"
|
id="windowOutput"
|
||||||
v-model="metric.isWindowOutput"
|
v-model="metric.isWindowOutput"
|
||||||
/>
|
/>
|
||||||
<FormCheck.Label class="font-bold" for="windowOutput">Window Output</FormCheck.Label>
|
<FormCheck.Label class="font-bold" for="windowOutput">Output Intervals</FormCheck.Label>
|
||||||
</FormCheck>
|
</FormCheck>
|
||||||
<div v-if="metric.isWindowOutput && metric.output" class="flex flex-col">
|
<div v-if="metric.isWindowOutput && metric.output" class="flex flex-col">
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3">
|
||||||
@ -195,7 +209,7 @@
|
|||||||
v-model="metric.output.type"
|
v-model="metric.output.type"
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].output.type`) }"
|
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].output.type`) }"
|
||||||
>
|
>
|
||||||
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS" :key="behaviorIndex">
|
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS_OUTPUT" :key="behaviorIndex">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
</Select>
|
</Select>
|
||||||
@ -276,48 +290,41 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<FormCheck class="mb-2">
|
<div class="flex flex-col">
|
||||||
<FormCheck.Input
|
<Label>Level</Label>
|
||||||
class="border"
|
<Select
|
||||||
type="checkbox"
|
v-model="metric.level"
|
||||||
id="windowInputRaw"
|
@change="emit('levelChangeHandler', index, $event as HTMLElementEvent<HTMLSelectElement>)"
|
||||||
v-model="metric.isWindowInputRaw"
|
:class="{
|
||||||
/>
|
'input--invalid': v.level?.$error || hasBackendError(`metrics[${index}].level`)
|
||||||
<FormCheck.Label class="font-bold" for="windowInputRaw">Window Input</FormCheck.Label>
|
}"
|
||||||
</FormCheck>
|
>
|
||||||
<div v-if="metric.isWindowInputRaw && metric.inputRaw" class="flex space-x-3">
|
<option value="global">Global</option>
|
||||||
<div class="flex flex-col flex-grow">
|
<option value="components">Components</option>
|
||||||
<Label>Type</Label>
|
</Select>
|
||||||
<Select
|
</div>
|
||||||
class="w-auto capitalize"
|
|
||||||
v-model="metric.inputRaw.type"
|
<div v-if="metric.level === 'components' && metric.components" class="flex flex-col">
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.type`) }"
|
<Label>Components</Label>
|
||||||
>
|
<TomSelect
|
||||||
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS" :key="behaviorIndex">
|
v-model="metric.components"
|
||||||
{{ option }}
|
class="w-full"
|
||||||
|
multiple
|
||||||
|
:class="{
|
||||||
|
'input--invalid': v.components?.$error || hasBackendError(`metrics[${index}].components`)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template v-if="componentList.length">
|
||||||
|
<option
|
||||||
|
v-for="(option, componentOptionIndex) in componentList"
|
||||||
|
:key="componentOptionIndex"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
</option>
|
</option>
|
||||||
</Select>
|
</template>
|
||||||
</div>
|
<template v-else> <option>No keys available</option> </template>
|
||||||
<div class="flex flex-col flex-grow">
|
</TomSelect>
|
||||||
<Label>Interval</Label>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
v-model="metric.inputRaw.interval"
|
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.interval`) }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col flex-grow">
|
|
||||||
<Label>Unit</Label>
|
|
||||||
<Select
|
|
||||||
class="w-auto capitalize"
|
|
||||||
v-model="metric.inputRaw.unit"
|
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.unit`) }"
|
|
||||||
>
|
|
||||||
<option v-for="(option, timeUnitIndex) in UNIT_TIME_OPTIONS" :key="timeUnitIndex">
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -329,7 +336,7 @@
|
|||||||
id="windowOutputRaw"
|
id="windowOutputRaw"
|
||||||
v-model="metric.isWindowOutputRaw"
|
v-model="metric.isWindowOutputRaw"
|
||||||
/>
|
/>
|
||||||
<FormCheck.Label class="font-bold" for="windowOutputRaw">Window Output</FormCheck.Label>
|
<FormCheck.Label class="font-bold" for="windowOutputRaw">Output Intervals</FormCheck.Label>
|
||||||
</FormCheck>
|
</FormCheck>
|
||||||
<div v-if="metric.isWindowOutputRaw && metric.outputRaw" class="flex flex-col">
|
<div v-if="metric.isWindowOutputRaw && metric.outputRaw" class="flex flex-col">
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3">
|
||||||
@ -388,7 +395,7 @@ import { Disclosure } from "@/base-components/Headless"
|
|||||||
import { ValidateEach } from "@vuelidate/components"
|
import { ValidateEach } from "@vuelidate/components"
|
||||||
import { FormCheck } from "@/base-components/Form"
|
import { FormCheck } from "@/base-components/Form"
|
||||||
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
|
||||||
import { UNIT_TIME_OPTIONS, BEHAVIOR_OPTIONS } from "@/constants"
|
import { UNIT_TIME_OPTIONS, BEHAVIOR_OPTIONS, BEHAVIOR_OPTIONS_INPUT ,BEHAVIOR_OPTIONS_OUTPUT} from "@/constants"
|
||||||
import Select from "@/base-components/Form/FormSelect.vue"
|
import Select from "@/base-components/Form/FormSelect.vue"
|
||||||
import Label from "@/base-components/Form/FormLabel.vue"
|
import Label from "@/base-components/Form/FormLabel.vue"
|
||||||
import Input from "@/base-components/Form/FormInput.vue"
|
import Input from "@/base-components/Form/FormInput.vue"
|
||||||
@ -405,9 +412,11 @@ const emit = defineEmits<{
|
|||||||
}>()
|
}>()
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
metrics: Array<IMetricComposite | IMetricRaw>
|
metrics: Array<IMetricComposite | IMetricRaw>
|
||||||
componentList: Array<{ label: string; value: string }>
|
componentList: Array<{ label: string; value: string }>,
|
||||||
|
templateNames: Array<string>
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
localMetrics,
|
localMetrics,
|
||||||
getValidationRules,
|
getValidationRules,
|
||||||
|
@ -254,51 +254,7 @@
|
|||||||
<Lucide icon="Trash2" class="ml-3 text-danger" @click="removeSetting(metric, settingIndex)" />
|
<Lucide icon="Trash2" class="ml-3 text-danger" @click="removeSetting(metric, settingIndex)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<FormCheck class="mb-2">
|
|
||||||
<FormCheck.Input
|
|
||||||
class="border"
|
|
||||||
type="checkbox"
|
|
||||||
id="windowInputRaw"
|
|
||||||
v-model="metric.isWindowInputRaw"
|
|
||||||
/>
|
|
||||||
<FormCheck.Label class="font-bold" for="windowInputRaw">Window Input</FormCheck.Label>
|
|
||||||
</FormCheck>
|
|
||||||
<div v-if="metric.isWindowInputRaw && metric.inputRaw" class="flex space-x-3">
|
|
||||||
<div class="flex flex-col flex-grow">
|
|
||||||
<Label>Type</Label>
|
|
||||||
<Select
|
|
||||||
class="w-auto capitalize"
|
|
||||||
v-model="metric.inputRaw.type"
|
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.type`) }"
|
|
||||||
>
|
|
||||||
<option v-for="(option, behaviorIndex) in BEHAVIOR_OPTIONS" :key="behaviorIndex">
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col flex-grow">
|
|
||||||
<Label>Interval</Label>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
v-model="metric.inputRaw.interval"
|
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.interval`) }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col flex-grow">
|
|
||||||
<Label>Unit</Label>
|
|
||||||
<Select
|
|
||||||
class="w-auto capitalize"
|
|
||||||
v-model="metric.inputRaw.unit"
|
|
||||||
:class="{ 'input--invalid': hasBackendError(`metrics[${index}].input.unit`) }"
|
|
||||||
>
|
|
||||||
<option v-for="(option, timeUnitIndex) in UNIT_TIME_OPTIONS" :key="timeUnitIndex">
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<FormCheck class="mb-2">
|
<FormCheck class="mb-2">
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
<Templates :templates="templates" />
|
<Templates :templates="templates" />
|
||||||
<Parameters :parameters="parameters" :templateNames="templateNames" />
|
<Parameters :parameters="parameters" :templateNames="templateNames" />
|
||||||
|
|
||||||
<Metrics :metrics="metrics" :componentList="props.payload.componentList" />
|
<Metrics :metrics="metrics" :componentList="props.payload.componentList"
|
||||||
|
:templateNames="templateNames"/>
|
||||||
|
|
||||||
<div class="flex flex-col space-y-5">
|
<div class="flex flex-col space-y-5">
|
||||||
<p class="text-2xl">SLO</p>
|
<p class="text-2xl">SLO</p>
|
||||||
@ -55,6 +56,7 @@ const props = withDefaults(defineProps<MetricsProps>(), {
|
|||||||
{
|
{
|
||||||
type: "composite",
|
type: "composite",
|
||||||
name: "",
|
name: "",
|
||||||
|
template: "",
|
||||||
formula: "",
|
formula: "",
|
||||||
isWindowInput: true,
|
isWindowInput: true,
|
||||||
isWindowOutput: true,
|
isWindowOutput: true,
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col box p-5 flex-grow space-y-5">
|
<div class="flex flex-col box p-5 flex-grow space-y-5">
|
||||||
<div class="flex items-center space-x-4">
|
|
||||||
<p class="text-2xl">Resources</p>
|
|
||||||
<Lucide icon="PlusCircle" @click="redirectToResources" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-grow overflow-y-auto h-0">
|
<div class="flex-grow overflow-y-auto h-0">
|
||||||
<div
|
<div
|
||||||
v-for="(resource, index) in resources"
|
v-for="(resource, index) in resources"
|
||||||
@ -58,6 +53,7 @@ const props = withDefaults(defineProps<ResourcesProps>(), {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const resources = computed<Array<IAppResource>>(() =>
|
const resources = computed<Array<IAppResource>>(() =>
|
||||||
|
|
||||||
resourceStore.resources.results.map((resource) => {
|
resourceStore.resources.results.map((resource) => {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const isEnabled = props.payload.appResources
|
const isEnabled = props.payload.appResources
|
||||||
@ -65,7 +61,7 @@ const resources = computed<Array<IAppResource>>(() =>
|
|||||||
return {
|
return {
|
||||||
uuid: resource.uuid,
|
uuid: resource.uuid,
|
||||||
title: resource.title,
|
title: resource.title,
|
||||||
platform: resource.platform,
|
platform: resource.platform.title,
|
||||||
enabled: isEnabled
|
enabled: isEnabled
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
returnRouteName="applications"
|
returnRouteName="applications"
|
||||||
:responseErrorMessages="responseErrorMessages"
|
:responseErrorMessages="responseErrorMessages"
|
||||||
:v$="v$"
|
:v$="v$"
|
||||||
|
:save-enabled="applicationData.status =='draft'"
|
||||||
@saveClick="saveClickHandler"
|
@saveClick="saveClickHandler"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
@ -72,6 +73,7 @@ const props = withDefaults(defineProps<ApplicationProps>(), {
|
|||||||
isWindowInput: true,
|
isWindowInput: true,
|
||||||
isWindowOutput: true,
|
isWindowOutput: true,
|
||||||
level: "global",
|
level: "global",
|
||||||
|
template: "",
|
||||||
components: [],
|
components: [],
|
||||||
input: {
|
input: {
|
||||||
type: "all",
|
type: "all",
|
||||||
|
40
gui/src/components/DebugInfo/DebugInfo.vue
Normal file
40
gui/src/components/DebugInfo/DebugInfo.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<Menu>
|
||||||
|
<Menu.Button
|
||||||
|
class="flex items-center justify-center w-8 h-8 overflow-hidden rounded-full shadow-lg image-fit zoom-in intro-x uppercase"
|
||||||
|
>
|
||||||
|
<Lucide icon="Info" class="w-5 h-5 text-slate-300 intro-x cursor-pointer"/>
|
||||||
|
</Menu.Button>
|
||||||
|
|
||||||
|
<Menu.Items
|
||||||
|
class="w-56 mt-px relative bg-primary/80 before:block before:absolute before:bg-black before:inset-0 before:rounded-md before:z-[-1] text-white"
|
||||||
|
>
|
||||||
|
<Menu.Header class="font-normal">
|
||||||
|
<div class="font-medium">App Information</div>
|
||||||
|
</Menu.Header>
|
||||||
|
<Menu.Divider class="bg-white/[0.08]" />
|
||||||
|
<Menu.Item class="hover:bg-white/5">
|
||||||
|
<div class="dark:text-slate-300">
|
||||||
|
{{ backend }}<br/>
|
||||||
|
{{ environment }}<br/>
|
||||||
|
{{ build_id }}<br/>
|
||||||
|
{{ context }}<br/>
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {Menu} from "@/base-components/Headless";
|
||||||
|
import Lucide from "@/base-components/Lucide";
|
||||||
|
|
||||||
|
const backend = import.meta.env.VITE_API_URL
|
||||||
|
const environment = import.meta.env.NODE_VERSION
|
||||||
|
const build_id = import.meta.env.BUILD_ID
|
||||||
|
const context = import.meta.env.CONTEXT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
@ -34,100 +34,8 @@
|
|||||||
<Breadcrumb.Link to="/" :active="true"> Dashboard </Breadcrumb.Link>
|
<Breadcrumb.Link to="/" :active="true"> Dashboard </Breadcrumb.Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
<!-- END: Breadcrumb -->
|
<!-- END: Breadcrumb -->
|
||||||
<!-- BEGIN: Search -->
|
|
||||||
<div class="relative mr-3 intro-x sm:mr-6">
|
|
||||||
<div class="relative hidden sm:block">
|
|
||||||
<FormInput
|
|
||||||
type="text"
|
|
||||||
class="border-transparent w-56 shadow-none rounded-full bg-slate-200 pr-8 transition-[width] duration-300 ease-in-out focus:border-transparent focus:w-72 dark:bg-darkmode-400"
|
|
||||||
placeholder="Search..."
|
|
||||||
@focus="showSearchDropdown"
|
|
||||||
@blur="hideSearchDropdown"
|
|
||||||
/>
|
|
||||||
<Lucide
|
|
||||||
icon="Search"
|
|
||||||
class="absolute inset-y-0 right-0 w-5 h-5 my-auto mr-3 text-slate-600 dark:text-slate-500"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<a class="relative text-white/70 sm:hidden" href="">
|
|
||||||
<Lucide icon="Search" class="w-5 h-5 dark:text-slate-500" />
|
|
||||||
</a>
|
|
||||||
<TransitionRoot
|
|
||||||
as="template"
|
|
||||||
:show="searchDropdown"
|
|
||||||
enter="transition-all ease-linear duration-150"
|
|
||||||
enterFrom="mt-5 invisible opacity-0 translate-y-1"
|
|
||||||
enterTo="mt-[3px] visible opacity-100 translate-y-0"
|
|
||||||
entered="mt-[3px]"
|
|
||||||
leave="transition-all ease-linear duration-150"
|
|
||||||
leaveFrom="mt-[3px] visible opacity-100 translate-y-0"
|
|
||||||
leaveTo="mt-5 invisible opacity-0 translate-y-1"
|
|
||||||
>
|
|
||||||
<div class="absolute right-0 z-10 mt-[3px]">
|
|
||||||
<div class="w-[450px] p-5 box">
|
|
||||||
<div class="mb-2 font-medium">Pages</div>
|
|
||||||
<div class="mb-5">
|
|
||||||
<a href="" class="flex items-center">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-8 h-8 rounded-full bg-success/20 dark:bg-success/10 text-success"
|
|
||||||
>
|
|
||||||
<Lucide icon="Inbox" class="w-4 h-4" />
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">Mail Settings</div>
|
|
||||||
</a>
|
|
||||||
<a href="" class="flex items-center mt-2">
|
|
||||||
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-pending/10 text-pending">
|
|
||||||
<Lucide icon="Users" class="w-4 h-4" />
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">Users & Permissions</div>
|
|
||||||
</a>
|
|
||||||
<a href="" class="flex items-center mt-2">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-8 h-8 rounded-full bg-primary/10 dark:bg-primary/20 text-primary/80"
|
|
||||||
>
|
|
||||||
<Lucide icon="CreditCard" class="w-4 h-4" />
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">Transactions Report</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2 font-medium">Users</div>
|
|
||||||
<div class="mb-5">
|
|
||||||
<a
|
|
||||||
v-for="(faker, fakerKey) in _.take(fakerData, 4)"
|
|
||||||
:key="fakerKey"
|
|
||||||
href=""
|
|
||||||
class="flex items-center mt-2"
|
|
||||||
>
|
|
||||||
<div class="w-8 h-8 image-fit">
|
|
||||||
<img alt="Midone Tailwind HTML Admin Template" class="rounded-full" :src="faker.photos[0]" />
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">{{ faker.users[0].name }}</div>
|
|
||||||
<div class="w-48 ml-auto text-xs text-right truncate text-slate-500">
|
|
||||||
{{ faker.users[0].email }}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2 font-medium">Products</div>
|
|
||||||
<a
|
|
||||||
v-for="(faker, fakerKey) in _.take(fakerData, 4)"
|
|
||||||
:key="fakerKey"
|
|
||||||
href=""
|
|
||||||
class="flex items-center mt-2"
|
|
||||||
>
|
|
||||||
<div class="w-8 h-8 image-fit">
|
|
||||||
<img alt="Midone Tailwind HTML Admin Template" class="rounded-full" :src="faker.images[0]" />
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">{{ faker.products[0].name }}</div>
|
|
||||||
<div class="w-48 ml-auto text-xs text-right truncate text-slate-500">
|
|
||||||
{{ faker.products[0].category }}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TransitionRoot>
|
|
||||||
</div>
|
|
||||||
<!-- END: Search -->
|
|
||||||
<!-- BEGIN: DARK -->
|
<!-- BEGIN: DARK -->
|
||||||
|
<DebugInfo class="mr-4" />
|
||||||
<DarkModeSwitcher class="mr-4" />
|
<DarkModeSwitcher class="mr-4" />
|
||||||
<!-- END: DARK -->
|
<!-- END: DARK -->
|
||||||
<!-- BEGIN: Account Menu -->
|
<!-- BEGIN: Account Menu -->
|
||||||
@ -173,6 +81,7 @@ import Breadcrumb from "@/base-components/Breadcrumb"
|
|||||||
import Logo from "@/base-components/Logo"
|
import Logo from "@/base-components/Logo"
|
||||||
import { FormInput } from "@/base-components/Form"
|
import { FormInput } from "@/base-components/Form"
|
||||||
import { Menu } from "@/base-components/Headless"
|
import { Menu } from "@/base-components/Headless"
|
||||||
|
import DebugInfo from "@/components/DebugInfo/DebugInfo.vue";
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -1,50 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col text-start">
|
<div class="flex flex-col text-start">
|
||||||
<slot name="title"></slot>
|
<slot name="title"></slot>
|
||||||
<Dialog.Description class="flex-col space-y-4 p-8">
|
<Dialog.Description>
|
||||||
<div class="flex flex-col">
|
<ResourceForm :resource-data="resourceData" :rules="rules"/>
|
||||||
<Label>Name</Label>
|
|
||||||
<Input
|
|
||||||
type="email"
|
|
||||||
v-model="resourceData.title"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.title.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>Type</Label>
|
|
||||||
<Select
|
|
||||||
v-model="resourceData.platform"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.platform.$error
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<option v-for="(platform, index) in platformsOptions" :key="index" :value="platform.uuid">
|
|
||||||
{{ platform.title }}
|
|
||||||
</option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>App ID</Label>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
v-model="resourceData.appId"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.appId.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>App Secret</Label>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
v-model="resourceData.appSecret"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.appSecret.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Dialog.Description>
|
</Dialog.Description>
|
||||||
<Dialog.Footer>
|
<Dialog.Footer>
|
||||||
<Button type="button" variant="outline-secondary" @click="closeModal(false)" class="w-20 mr-4"> Cancel </Button>
|
<Button type="button" variant="outline-secondary" @click="closeModal(false)" class="w-20 mr-4"> Cancel </Button>
|
||||||
@ -54,29 +12,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from "vue"
|
import {reactive} from "vue"
|
||||||
import { useUIStore } from "@/store/modules/ui.ts"
|
import {useUIStore} from "@/store/modules/ui.ts"
|
||||||
import { useResourceStore } from "@/store/modules/resources.ts"
|
import {useResourceStore} from "@/store/modules/resources.ts"
|
||||||
import { extractExternalResults } from "@/utils/helper.ts"
|
import {extractExternalResults} from "@/utils/helper.ts"
|
||||||
import { useVuelidate } from "@vuelidate/core"
|
import {useVuelidate} from "@vuelidate/core"
|
||||||
import { required } from "@vuelidate/validators"
|
import {required} from "@vuelidate/validators"
|
||||||
import { Dialog } from "@/base-components/Headless"
|
import {Dialog} from "@/base-components/Headless"
|
||||||
import Button from "@/base-components/Button"
|
import Button from "@/base-components/Button"
|
||||||
import Label from "@/base-components/Form/FormLabel.vue"
|
import {SNACKBAR_MESSAGE_TYPES} from "@/constants"
|
||||||
import Input from "@/base-components/Form/FormInput.vue"
|
import {IResourcePayload} from "@/types/resource.ts"
|
||||||
import Select from "@/base-components/Form/FormSelect.vue"
|
import ResourceForm from "@/components/Modal/ResourceForm.vue";
|
||||||
import { SNACKBAR_MESSAGE_TYPES } from "@/constants"
|
import {IPlatform} from "@/interfaces/platform.interface.ts";
|
||||||
import { IResourcePayload } from "@/types/resource.ts"
|
|
||||||
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
|
||||||
|
|
||||||
const resourceStore = useResourceStore()
|
const resourceStore = useResourceStore()
|
||||||
const uiStore = useUIStore()
|
const uiStore = useUIStore()
|
||||||
|
|
||||||
const resourceData = reactive<IResourcePayload>({
|
const resourceData = reactive<IResourcePayload>({
|
||||||
title: "",
|
title: "",
|
||||||
platform: "",
|
platform: {"uuid":'','title':''} as IPlatform,
|
||||||
appId: "",
|
_platform: [{"uuid":'','title':''} as IPlatform], // TODO Remove this
|
||||||
appSecret: ""
|
securityGroup:"",
|
||||||
|
subnet:"",
|
||||||
|
endpoint:"",
|
||||||
|
identityVersion:"",
|
||||||
|
defaultNetwork:"",
|
||||||
|
credentials: {
|
||||||
|
user:"",
|
||||||
|
secret:"",
|
||||||
|
domain:"",
|
||||||
|
},
|
||||||
|
sshCredentials: {
|
||||||
|
username:"",
|
||||||
|
privateKey:"",
|
||||||
|
keyPairName:"",
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// HACK: https://github.com/vuelidate/vuelidate/issues/1147
|
// HACK: https://github.com/vuelidate/vuelidate/issues/1147
|
||||||
@ -84,9 +54,7 @@ const externalServerValidation = () => true
|
|||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
title: { required, externalServerValidation },
|
title: { required, externalServerValidation },
|
||||||
platform: { required, externalServerValidation },
|
platform: { required, externalServerValidation }
|
||||||
appId: { required, externalServerValidation },
|
|
||||||
appSecret: { required, externalServerValidation }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const $externalResults = reactive({})
|
const $externalResults = reactive({})
|
||||||
@ -96,8 +64,13 @@ const closeModal = (skipConfirmation: boolean = false) => {
|
|||||||
uiStore.setModalWindowState(null, skipConfirmation)
|
uiStore.setModalWindowState(null, skipConfirmation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const createResource = async () => {
|
const createResource = async () => {
|
||||||
if (!(await v$.value.$validate())) return
|
if (!(await v$.value.$validate())){
|
||||||
|
console.log("Failed validation")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resourceStore
|
resourceStore
|
||||||
.createResource(resourceData)
|
.createResource(resourceData)
|
||||||
.then((createdResource) => {
|
.then((createdResource) => {
|
||||||
@ -113,11 +86,4 @@ const createResource = async () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const platformsOptions = ref<Array<IPlatform>>([])
|
|
||||||
|
|
||||||
const getPlatforms = async () => {
|
|
||||||
platformsOptions.value = await resourceStore.getPlatforms()
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlatforms()
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,51 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col text-start">
|
<div class="flex flex-col text-start">
|
||||||
<slot name="title"></slot>
|
<slot name="title"></slot>
|
||||||
<Dialog.Description class="flex-col space-y-4 p-8">
|
<ResourceForm :resource-data="resourceData" :rules="rules"/>
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>Name</Label>
|
|
||||||
<Input
|
|
||||||
type="email"
|
|
||||||
v-model="resourceData.title"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.title?.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>Type</Label>
|
|
||||||
<Select
|
|
||||||
v-model="resourceData.platform"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.platform?.$error
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<option v-for="(platform, index) in platformsOptions" :key="index" :value="platform.uuid">
|
|
||||||
{{ platform.title }}
|
|
||||||
</option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>App ID</Label>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
v-model="resourceData.appId"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.appId?.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<Label>App Secret</Label>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
v-model="resourceData.appSecret"
|
|
||||||
:class="{
|
|
||||||
'input--invalid': v$.appSecret?.$error
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Dialog.Description>
|
|
||||||
<Dialog.Footer>
|
<Dialog.Footer>
|
||||||
<Button type="button" variant="outline-secondary" @click="closeModal(false)" class="w-20 mr-4"> Cancel </Button>
|
<Button type="button" variant="outline-secondary" @click="closeModal(false)" class="w-20 mr-4"> Cancel </Button>
|
||||||
<Button variant="primary" type="button" class="w-20" @click="editResource"> Save </Button>
|
<Button variant="primary" type="button" class="w-20" @click="editResource"> Save </Button>
|
||||||
@ -68,6 +24,7 @@ import Select from "@/base-components/Form/FormSelect.vue"
|
|||||||
import { SNACKBAR_MESSAGE_TYPES } from "@/constants"
|
import { SNACKBAR_MESSAGE_TYPES } from "@/constants"
|
||||||
import { IResourcePayload } from "@/types/resource.ts"
|
import { IResourcePayload } from "@/types/resource.ts"
|
||||||
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
||||||
|
import ResourceForm from "@/components/Modal/ResourceForm.vue";
|
||||||
|
|
||||||
interface ResourceEditingProps {
|
interface ResourceEditingProps {
|
||||||
payload: IResourcePayload & { uuid: string }
|
payload: IResourcePayload & { uuid: string }
|
||||||
@ -78,21 +35,14 @@ const props = defineProps<ResourceEditingProps>()
|
|||||||
const resourceStore = useResourceStore()
|
const resourceStore = useResourceStore()
|
||||||
const uiStore = useUIStore()
|
const uiStore = useUIStore()
|
||||||
|
|
||||||
const resourceData = reactive<IResourcePayload>({
|
const resourceData = reactive<IResourcePayload>(props.payload)
|
||||||
title: props.payload.title ?? "",
|
|
||||||
platform: props.payload.platform ?? "",
|
|
||||||
appId: props.payload.appId ?? "",
|
|
||||||
appSecret: props.payload.appSecret ?? ""
|
|
||||||
})
|
|
||||||
|
|
||||||
// HACK: https://github.com/vuelidate/vuelidate/issues/1147
|
// HACK: https://github.com/vuelidate/vuelidate/issues/1147
|
||||||
const externalServerValidation = () => true
|
const externalServerValidation = () => true
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
title: { required, externalServerValidation },
|
title: { required, externalServerValidation },
|
||||||
platform: { required, externalServerValidation },
|
platform: { required, externalServerValidation }
|
||||||
appId: { required, externalServerValidation },
|
|
||||||
appSecret: { required, externalServerValidation }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const $externalResults = reactive({})
|
const $externalResults = reactive({})
|
||||||
@ -103,8 +53,11 @@ const closeModal = (skipConfirmation: boolean = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editResource = async () => {
|
const editResource = async () => {
|
||||||
if (!(await v$.value.$validate())) return
|
const validate = await v$.value.$validate()
|
||||||
if (!(await v$.value.$validate())) return
|
if (!validate){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resourceStore
|
resourceStore
|
||||||
.editResource(props.payload.uuid, resourceData)
|
.editResource(props.payload.uuid, resourceData)
|
||||||
.then((editedResource) => {
|
.then((editedResource) => {
|
||||||
@ -120,11 +73,5 @@ const editResource = async () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const platformsOptions = ref<Array<IPlatform>>([])
|
|
||||||
|
|
||||||
const getPlatforms = async () => {
|
|
||||||
platformsOptions.value = await resourceStore.getPlatforms()
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlatforms()
|
|
||||||
</script>
|
</script>
|
||||||
|
182
gui/src/components/Modal/ResourceForm.vue
Normal file
182
gui/src/components/Modal/ResourceForm.vue
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog.Description class="grid grid-cols-3 gap-4 p-4" :class=" availableInPlatform(['OPENSTACK','AWS']) ? 'grid-cols-3' : 'grid-cols-2' "
|
||||||
|
>
|
||||||
|
<div class="col-span-3 p-0">
|
||||||
|
<div class="mb-3">
|
||||||
|
<Label>Name</Label>
|
||||||
|
<Input
|
||||||
|
type="email"
|
||||||
|
v-model="resourceData.title"
|
||||||
|
:class="{
|
||||||
|
'input--invalid': v$.title.$error
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Platform</Label>
|
||||||
|
<Select
|
||||||
|
v-model="resourceData.platform.uuid"
|
||||||
|
:class="{
|
||||||
|
'input--invalid': v$.platform.$error
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<option v-for="(platform, index) in platformsOptions" :key="index" :value="platform.uuid">
|
||||||
|
{{ platform.title }}
|
||||||
|
</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h3 class="font-bold text-lg mb-2">General</h3>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Default Network</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.defaultNetwork"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Subnet</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.subnet"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Endpoint</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Identity Version</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.identityVersion"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Security Group</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.securityGroup"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h3 class="font-bold text-lg mb-2">Credentials</h3>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Username</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.credentials.user"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Secret</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.credentials.secret"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label>Domain</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.credentials.domain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
|
||||||
|
<h3 class="font-bold text-lg mb-2"
|
||||||
|
v-if="availableInPlatform(['OPENSTACK','AWS'])"
|
||||||
|
>SSH Credentials</h3>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex flex-col"
|
||||||
|
v-if="availableInPlatform(['OPENSTACK','AWS'])"
|
||||||
|
>
|
||||||
|
<Label>Username</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.sshCredentials.username"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col"
|
||||||
|
v-if="availableInPlatform(['OPENSTACK','AWS'])"
|
||||||
|
>
|
||||||
|
<Label>Key Pair Name</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="resourceData.sshCredentials.keyPairName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col"
|
||||||
|
v-if="availableInPlatform(['OPENSTACK','AWS'])"
|
||||||
|
>
|
||||||
|
<Label>Key Private Key</Label>
|
||||||
|
<FormTextarea
|
||||||
|
v-model="resourceData.sshCredentials.privateKey"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Dialog.Description>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from "vue"
|
||||||
|
import {FormTextarea} from "@/base-components/Form";
|
||||||
|
import { Dialog } from "@/base-components/Headless"
|
||||||
|
import Input from "../../base-components/Form/FormInput.vue";
|
||||||
|
import Label from "../../base-components/Form/FormLabel.vue";
|
||||||
|
import Select from "../../base-components/Form/FormSelect.vue";
|
||||||
|
import _ from "lodash";
|
||||||
|
import {IPlatform} from "@/interfaces/platform.interface.ts";
|
||||||
|
import {useResourceStore} from "@/store/modules/resources.ts";
|
||||||
|
import {IResourcePayload} from "@/types/resource.ts";
|
||||||
|
import {useVuelidate} from "@vuelidate/core";
|
||||||
|
|
||||||
|
const resourceStore = useResourceStore()
|
||||||
|
|
||||||
|
const props = defineProps(['resourceData','rules'])
|
||||||
|
|
||||||
|
const resourceData = ref<IResourcePayload>(props.resourceData)
|
||||||
|
const rules = ref<IResourcePayload>(props.rules)
|
||||||
|
|
||||||
|
console.log("Resource Data", resourceData)
|
||||||
|
|
||||||
|
const $externalResults = reactive({})
|
||||||
|
const v$ = useVuelidate(rules.value, resourceData.value, { $externalResults })
|
||||||
|
|
||||||
|
|
||||||
|
const platformsOptions = ref<Array<IPlatform>>([])
|
||||||
|
const availableInPlatform = (platforms:Array<string>): boolean => {
|
||||||
|
|
||||||
|
const to_uuid:Array<string> = []
|
||||||
|
const availableOptions = _.each(platformsOptions.value, (k)=>{
|
||||||
|
if(platforms.includes(k.title)){
|
||||||
|
to_uuid.push(k.uuid)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return to_uuid.includes(resourceData.value.platform.uuid)
|
||||||
|
}
|
||||||
|
const getPlatforms = async () => {
|
||||||
|
platformsOptions.value = await resourceStore.getPlatforms()
|
||||||
|
}
|
||||||
|
getPlatforms()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog static size="xl" :open="Boolean(openedModalWindow)" @close="() => null">
|
<Dialog static scrollable size="xl" :open="Boolean(openedModalWindow)" @close="() => null">
|
||||||
<Dialog.Panel>
|
<Dialog.Panel>
|
||||||
<Snackbar v-if="uiStore.snackbarMessage" />
|
<Snackbar v-if="uiStore.snackbarMessage" />
|
||||||
<component v-if="openedModalWindow" :is="components[openedModalWindow.name]" :payload="openedModalWindow.payload">
|
<component v-if="openedModalWindow" :is="components[openedModalWindow.name]" :payload="openedModalWindow.payload">
|
||||||
|
@ -3,7 +3,7 @@ import MODAL_WINDOW_NAMES from "./modalWindowNames.ts"
|
|||||||
import PLATFORM_COLOR from "./platformColors.ts"
|
import PLATFORM_COLOR from "./platformColors.ts"
|
||||||
import OPERATORS from "./operators.ts"
|
import OPERATORS from "./operators.ts"
|
||||||
import SNACKBAR_MESSAGE_TYPES from "./snackbarMessageTypes.ts"
|
import SNACKBAR_MESSAGE_TYPES from "./snackbarMessageTypes.ts"
|
||||||
import { behaviorOptions as BEHAVIOR_OPTIONS, unitTimeOptions as UNIT_TIME_OPTIONS } from "./metricsOptions.ts"
|
import { behaviorOptions as BEHAVIOR_OPTIONS, behaviorOptionsInput as BEHAVIOR_OPTIONS_INPUT,behaviorOptionsOutput as BEHAVIOR_OPTIONS_OUTPUT, unitTimeOptions as UNIT_TIME_OPTIONS } from "./metricsOptions.ts"
|
||||||
|
|
||||||
export {
|
export {
|
||||||
VALIDATION_MESSAGES,
|
VALIDATION_MESSAGES,
|
||||||
@ -11,6 +11,8 @@ export {
|
|||||||
PLATFORM_COLOR,
|
PLATFORM_COLOR,
|
||||||
OPERATORS,
|
OPERATORS,
|
||||||
BEHAVIOR_OPTIONS,
|
BEHAVIOR_OPTIONS,
|
||||||
|
BEHAVIOR_OPTIONS_INPUT,
|
||||||
|
BEHAVIOR_OPTIONS_OUTPUT,
|
||||||
UNIT_TIME_OPTIONS,
|
UNIT_TIME_OPTIONS,
|
||||||
SNACKBAR_MESSAGE_TYPES
|
SNACKBAR_MESSAGE_TYPES
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
export const behaviorOptions = ["all", "sliding"] as const
|
export const behaviorOptions = ["all", "sliding"] as const
|
||||||
export const unitTimeOptions = ["ms", "sec", "min", "hour", "day"] as const
|
export const behaviorOptionsInput = ["batch", "sliding"] as const
|
||||||
|
export const behaviorOptionsOutput = ["all", "first","last"] as const
|
||||||
|
export const unitTimeOptions = ["ms", "sec", "min", "hour", "day", "events",] as const
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
|
|
||||||
<Lucide v-if="application.status=='ready'" icon="PlayCircle" class="w-10 text-white" @click="deployApplication(application)" />
|
<Lucide icon="PlayCircle" class="w-10 text-white" @click="deployApplication(application)" />
|
||||||
<Lucide v-if="application.status=='draft' || application.status=='ready' || !application.status" icon="Pencil" class="w-10 text-warning" @click="toApplicationEditing(application)" />
|
<Lucide v-if="application.status=='draft' || application.status=='ready' || !application.status" icon="Pencil" class="w-10 text-warning" @click="toApplicationEditing(application)" />
|
||||||
<Lucide v-if="application.status=='draft' || application.status=='ready' || !application.status" icon="Trash2" class="w-10 text-danger" @click="removeApplication(application.uuid)" />
|
<Lucide v-if="application.status=='draft' || application.status=='ready' || !application.status" icon="Trash2" class="w-10 text-danger" @click="removeApplication(application.uuid)" />
|
||||||
</div>
|
</div>
|
||||||
@ -164,9 +164,7 @@ const removeApplication = (uuid: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toApplicationEditing = (application: IApplication) => {
|
const toApplicationEditing = (application: IApplication) => {
|
||||||
if(application.status == 'draft' || !application.status){
|
router.push({ name: "application", params: { appUuid: application.uuid } })
|
||||||
router.push({ name: "application", params: { appUuid: application.uuid } })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const deployApplication = (application: IApplication) =>{
|
const deployApplication = (application: IApplication) =>{
|
||||||
|
|
||||||
|
32
gui/src/containers/Applications/PolicyEditor/index.vue
Normal file
32
gui/src/containers/Applications/PolicyEditor/index.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col mt-8 intro-y">
|
||||||
|
<div class="flex flex-row justify-between items-center mb-4">
|
||||||
|
<h2 class="text-base uppercase">Policy Editor</h2>
|
||||||
|
<Button variant="primary" class="uppercase" @click="publishPolicy">Publish</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="md:box flex-grow overflow-x-auto md:p-5" >
|
||||||
|
<MonacoEditor
|
||||||
|
v-model="policyStore.rules"
|
||||||
|
language="json"
|
||||||
|
class="min-h-[400px]"
|
||||||
|
id="json_policy_editor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {usePolicyStore} from "@/store/modules/policies.ts"
|
||||||
|
import Button from "@/base-components/Button/Button.vue"
|
||||||
|
import MonacoEditor from "@/base-components/MonacoEditor";
|
||||||
|
|
||||||
|
const policyStore = usePolicyStore()
|
||||||
|
|
||||||
|
const publishPolicy = async () => {
|
||||||
|
await policyStore.publishPolicies(policyStore.rules)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
@ -11,7 +11,7 @@
|
|||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Th class="border-b-0 whitespace-nowrap"> Name </Table.Th>
|
<Table.Th class="border-b-0 whitespace-nowrap"> Name </Table.Th>
|
||||||
<Table.Th class="border-b-0 whitespace-nowrap"> Platform </Table.Th>
|
<Table.Th class="border-b-0 whitespace-nowrap"> Platform </Table.Th>
|
||||||
<Table.Th class="border-b-0 whitespace-nowrap"> AppId </Table.Th>
|
<Table.Th class="border-b-0 whitespace-nowrap"> UUID </Table.Th>
|
||||||
<Table.Th class="border-b-0 whitespace-nowrap"> App Secret </Table.Th>
|
<Table.Th class="border-b-0 whitespace-nowrap"> App Secret </Table.Th>
|
||||||
<Table.Th class="border-b-0 whitespace-nowrap w-24"> Action </Table.Th>
|
<Table.Th class="border-b-0 whitespace-nowrap w-24"> Action </Table.Th>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
@ -21,35 +21,37 @@
|
|||||||
<Table.Td
|
<Table.Td
|
||||||
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
>
|
>
|
||||||
<div>{{ resource.title }}</div>
|
<div>
|
||||||
|
<strong>{{ resource.title }}</strong>
|
||||||
|
</div>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td
|
<Table.Td
|
||||||
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="resource.platform"
|
v-if="resource.platform"
|
||||||
class="px-4 rounded-2xl w-20 text-center uppercase"
|
class="px-4 rounded-2xl w-40 text-center uppercase"
|
||||||
:class="generateColor(resource.platform)"
|
:class="generateColor(resource.platform.uuid)"
|
||||||
>
|
>
|
||||||
{{ resource.platform }}
|
{{ resource.platform.title }}
|
||||||
</div>
|
</div>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td
|
<Table.Td
|
||||||
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
>
|
>
|
||||||
<div>{{ resource.appId }}</div>
|
<div>{{ resource.uuid }}</div>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td
|
<Table.Td
|
||||||
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
>
|
>
|
||||||
<div>{{ resource.appSecret }}</div>
|
<div>*************</div>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td
|
<Table.Td
|
||||||
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
>
|
>
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3">
|
||||||
<Lucide icon="Trash2" class="text-danger" @click="removeResource(resource.uuid)" />
|
<Lucide icon="Trash2" class="text-danger" @click="removeResource(resource.uuid)" />
|
||||||
<Lucide icon="Eye" @click="loadNodeCandidates(resource.uuid)" />
|
<Lucide icon="Eye" @click="retrieveAllCandidates(resource.uuid)" />
|
||||||
<Lucide icon="MoreVertical" :data-tooltip="`user-tooltip-${index}`" />
|
<Lucide icon="MoreVertical" :data-tooltip="`user-tooltip-${index}`" />
|
||||||
<TippyContent :to="`user-tooltip-${index}`" class="p-2">
|
<TippyContent :to="`user-tooltip-${index}`" class="p-2">
|
||||||
<Button variant="outline-warning" @click="openResourceEditingModal(resource)">Edit Resource</Button>
|
<Button variant="outline-warning" @click="openResourceEditingModal(resource)">Edit Resource</Button>
|
||||||
@ -70,8 +72,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box p-5 mt-3">
|
<div class="box p-5 mt-3" >
|
||||||
<NodeCandidatesTable />
|
<div class="flex-grow overflow-x-auto">
|
||||||
|
<Table class="border-spacing-y-[10px] border-separate -mt-2 min-w-full max-w-max w-max">
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th class="border-b-0 whitespace-nowrap"> Region </Table.Th>
|
||||||
|
<Table.Th class="border-b-0 whitespace-nowrap"> Instance Type </Table.Th>
|
||||||
|
<Table.Th class="border-b-0 whitespace-nowrap"> Vcores </Table.Th>
|
||||||
|
<Table.Th class="border-b-0 whitespace-nowrap"> Memory (GB) </Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
<Table.Tr v-for="(node, index) in nodeCandidates" :key="index">
|
||||||
|
<Table.Td
|
||||||
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
|
>
|
||||||
|
{{ node.region }}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td
|
||||||
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
|
>
|
||||||
|
{{ node.instanceType }}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td
|
||||||
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
|
>
|
||||||
|
{{ node.virtualCores }}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td
|
||||||
|
class="first:rounded-l-md last:rounded-r-md bg-white border-b-0 dark:bg-darkmode-600 shadow-[20px_3px_20px_#0000000b]"
|
||||||
|
>
|
||||||
|
{{ node.memory }}
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -80,8 +117,7 @@
|
|||||||
import { computed, ref } from "vue"
|
import { computed, ref } from "vue"
|
||||||
import { useResourceStore } from "@/store/modules/resources.ts"
|
import { useResourceStore } from "@/store/modules/resources.ts"
|
||||||
import { useUIStore } from "@/store/modules/ui.ts"
|
import { useUIStore } from "@/store/modules/ui.ts"
|
||||||
import NodeCandidatesTable from "./NodeCandidatesTable.vue"
|
import {INodeCandidate, IResource} from "@/interfaces/resources.interface.ts"
|
||||||
import { IResource } from "@/interfaces/resources.interface.ts"
|
|
||||||
import { MODAL_WINDOW_NAMES, SNACKBAR_MESSAGE_TYPES } from "@/constants"
|
import { MODAL_WINDOW_NAMES, SNACKBAR_MESSAGE_TYPES } from "@/constants"
|
||||||
import Button from "@/base-components/Button/Button.vue"
|
import Button from "@/base-components/Button/Button.vue"
|
||||||
import Lucide from "@/base-components/Lucide/Lucide.vue"
|
import Lucide from "@/base-components/Lucide/Lucide.vue"
|
||||||
@ -91,12 +127,18 @@ import TippyContent from "@/base-components/TippyContent/TippyContent.vue"
|
|||||||
import { usePagination } from "@/composables/usePagination.ts"
|
import { usePagination } from "@/composables/usePagination.ts"
|
||||||
import { generateColor } from "@/utils/colors.ts"
|
import { generateColor } from "@/utils/colors.ts"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const resourceStore = useResourceStore()
|
const resourceStore = useResourceStore()
|
||||||
const uiStore = useUIStore()
|
const uiStore = useUIStore()
|
||||||
|
|
||||||
const resources = computed<Array<IResource>>(() => resourceStore.resources.results)
|
const resources = computed<Array<IResource>>(() => resourceStore.resources.results)
|
||||||
|
const nodeCandidates = computed<Array<INodeCandidate>>(() => resourceStore.candidates)
|
||||||
|
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
|
|
||||||
|
|
||||||
const rowsPerPage = ref(10)
|
const rowsPerPage = ref(10)
|
||||||
|
|
||||||
const rowsPerPageChange = (rows: number) => {
|
const rowsPerPageChange = (rows: number) => {
|
||||||
@ -109,10 +151,15 @@ const { paginatedArray, numberOfPages } = usePagination<IResource>({
|
|||||||
currentPage: currentPage
|
currentPage: currentPage
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const retrieveAllResources = async () => {
|
const retrieveAllResources = async () => {
|
||||||
await resourceStore.getAllResources()
|
await resourceStore.getAllResources()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const retrieveAllCandidates = async (uuid:string) => {
|
||||||
|
await resourceStore.getAllNodeCandidate(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
const removeResource = (uuid: string) => {
|
const removeResource = (uuid: string) => {
|
||||||
uiStore.setModalWindowState({
|
uiStore.setModalWindowState({
|
||||||
name: MODAL_WINDOW_NAMES.CONFIRM_DELETING_MODAL,
|
name: MODAL_WINDOW_NAMES.CONFIRM_DELETING_MODAL,
|
||||||
@ -130,8 +177,6 @@ const removeResource = (uuid: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadNodeCandidates = (uuid: string) => {}
|
|
||||||
|
|
||||||
const openResourceEditingModal = (resource: IResource) => {
|
const openResourceEditingModal = (resource: IResource) => {
|
||||||
uiStore.setModalWindowState({
|
uiStore.setModalWindowState({
|
||||||
name: MODAL_WINDOW_NAMES.RESOURCE_EDITING,
|
name: MODAL_WINDOW_NAMES.RESOURCE_EDITING,
|
||||||
|
@ -4,6 +4,8 @@ const ApplicationsOverview = () =>
|
|||||||
import(/* webpackChunkName: "ApplicationsOverview" */ "@/containers/Applications/Overview")
|
import(/* webpackChunkName: "ApplicationsOverview" */ "@/containers/Applications/Overview")
|
||||||
const ApplicationsResources = () =>
|
const ApplicationsResources = () =>
|
||||||
import(/* webpackChunkName: "ApplicationsResources" */ "@/containers/Applications/Resources")
|
import(/* webpackChunkName: "ApplicationsResources" */ "@/containers/Applications/Resources")
|
||||||
|
const ApplicationsPolicyEditor = () =>
|
||||||
|
import(/* webpackChunkName: "ApplicationsResources" */ "@/containers/Applications/PolicyEditor")
|
||||||
const ApplicationCreation = () =>
|
const ApplicationCreation = () =>
|
||||||
import(/* webpackChunkName: "ApplicationCreation" */ "@/containers/Applications/ApplicationCreation")
|
import(/* webpackChunkName: "ApplicationCreation" */ "@/containers/Applications/ApplicationCreation")
|
||||||
|
|
||||||
@ -32,6 +34,12 @@ const ApplicationsRoute: RouteRecordRaw = {
|
|||||||
name: "applications-resources",
|
name: "applications-resources",
|
||||||
component: ApplicationsResources
|
component: ApplicationsResources
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "policy-editor",
|
||||||
|
name: "policy-editor",
|
||||||
|
component: ApplicationsPolicyEditor
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: "creation",
|
path: "creation",
|
||||||
name: "application-creation",
|
name: "application-creation",
|
||||||
|
@ -24,6 +24,14 @@
|
|||||||
<!-- <p class="text-right">
|
<!-- <p class="text-right">
|
||||||
<a class="text-blue-600 text-sm font-light hover:underline"> Forgot Password? </a>
|
<a class="text-blue-600 text-sm font-light hover:underline"> Forgot Password? </a>
|
||||||
</p> -->
|
</p> -->
|
||||||
|
|
||||||
|
<div class="text-slate-200 dark:text-slate-800 text-center">
|
||||||
|
{{ environment }} | {{ build_id }} | {{ context }}
|
||||||
|
</div>
|
||||||
|
<div class="text-white dark:text-slate-800 text-center">
|
||||||
|
{{ backend }}
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -38,8 +46,12 @@ import { FormInput } from "@/base-components/Form"
|
|||||||
import { useUserStore } from "@/store/modules/user.ts"
|
import { useUserStore } from "@/store/modules/user.ts"
|
||||||
import { ICredentials } from "@/interfaces/user.interface.ts"
|
import { ICredentials } from "@/interfaces/user.interface.ts"
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const backend = import.meta.env.VITE_API_URL
|
||||||
|
const environment = import.meta.env.NODE_VERSION
|
||||||
|
const build_id = import.meta.env.BUILD_ID
|
||||||
|
const context = import.meta.env.CONTEXT
|
||||||
const form = reactive<ICredentials>({
|
const form = reactive<ICredentials>({
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: ""
|
||||||
|
@ -7,14 +7,15 @@ export interface IWindowController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IMetric {
|
export interface IMetric {
|
||||||
name: string
|
name: string,
|
||||||
|
level: "global" | "components"
|
||||||
|
components?: Array<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMetricComposite extends IMetric {
|
export interface IMetricComposite extends IMetric {
|
||||||
type: "composite"
|
type: "composite"
|
||||||
level: "global" | "components"
|
|
||||||
components?: Array<string>
|
|
||||||
formula: string
|
formula: string
|
||||||
|
template: string
|
||||||
isWindowInput: boolean
|
isWindowInput: boolean
|
||||||
isWindowOutput: boolean
|
isWindowOutput: boolean
|
||||||
input: IWindowController | null
|
input: IWindowController | null
|
||||||
@ -24,9 +25,7 @@ export interface IMetricComposite extends IMetric {
|
|||||||
export interface IMetricRaw extends IMetric {
|
export interface IMetricRaw extends IMetric {
|
||||||
type: "raw"
|
type: "raw"
|
||||||
sensor: string
|
sensor: string
|
||||||
isWindowInputRaw: boolean
|
|
||||||
isWindowOutputRaw: boolean
|
isWindowOutputRaw: boolean
|
||||||
inputRaw: IWindowController | null
|
|
||||||
outputRaw: IWindowController | null
|
outputRaw: IWindowController | null
|
||||||
config: Array<RawMetricConfigType>
|
config: Array<RawMetricConfigType>
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export interface IPlatform {
|
export interface IPlatform {
|
||||||
uuid: string
|
uuid: string
|
||||||
type: string
|
|
||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,49 @@
|
|||||||
|
import {IPlatform} from "@/interfaces/platform.interface.ts";
|
||||||
|
|
||||||
|
export interface ISSHCredentials{
|
||||||
|
username: string
|
||||||
|
keyPairName: string
|
||||||
|
privateKey: string
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICredentials{
|
||||||
|
user: string
|
||||||
|
secret: string
|
||||||
|
domain: string
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface IResource {
|
export interface IResource {
|
||||||
uuid: string
|
uuid: string
|
||||||
title: string
|
title: string
|
||||||
platform: string
|
securityGroup: string
|
||||||
|
subnet: string
|
||||||
|
endpoint: string
|
||||||
|
identityVersion: string
|
||||||
|
defaultNetwork: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
appId: string
|
credentials: ICredentials
|
||||||
appSecret: string
|
sshCredentials: ISSHCredentials
|
||||||
|
platform: IPlatform,
|
||||||
|
_platform: Array<IPlatform>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface IAppResource {
|
export interface IAppResource {
|
||||||
uuid: string
|
uuid: string
|
||||||
title: string
|
title: string
|
||||||
platform: string
|
platform: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface INodeCandidate {
|
||||||
|
id: number
|
||||||
|
region: string
|
||||||
|
instanceType: string
|
||||||
|
virtualCores: number
|
||||||
|
memory: number
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
export interface IUtilityFunction {
|
export interface IUtilityFunction {
|
||||||
functionName: string
|
functionName: string
|
||||||
functionType: "maximize" | "constant"
|
functionType: "maximize" | "constant" | "minimize"
|
||||||
functionExpression: string
|
functionExpression: string
|
||||||
functionExpressionVariables: Array<{ nameVariable: string; valueVariable: string }>
|
functionExpressionVariables: Array<{ nameVariable: string; valueVariable: string }>
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import {IApplication, IApplicationOverview} from "@/interfaces/application.interface.ts"
|
import {IApplication, IApplicationOverview} from "@/interfaces/application.interface.ts"
|
||||||
import {DeleteResponseType, DeployResponseType} from "@/types/responses.ts"
|
import {DeleteResponseType, DeployResponseType, PolicyResponseType} from "@/types/responses.ts"
|
||||||
import {IVariable} from "@/interfaces/variables.interface.ts"
|
import {IVariable} from "@/interfaces/variables.interface.ts"
|
||||||
import {IResource} from "@/interfaces/resources.interface.ts"
|
import {IResource} from "@/interfaces/resources.interface.ts"
|
||||||
import {ITemplate} from "@/interfaces/template.interface.ts"
|
import {ITemplate} from "@/interfaces/template.interface.ts"
|
||||||
@ -66,6 +66,7 @@ export default {
|
|||||||
level: metric.level,
|
level: metric.level,
|
||||||
components: metric.components,
|
components: metric.components,
|
||||||
name: metric.name,
|
name: metric.name,
|
||||||
|
template: metric.template,
|
||||||
formula: metric.formula,
|
formula: metric.formula,
|
||||||
isWindowInput: metric.isWindowInput,
|
isWindowInput: metric.isWindowInput,
|
||||||
input: {
|
input: {
|
||||||
@ -84,14 +85,10 @@ export default {
|
|||||||
return {
|
return {
|
||||||
type: metric.type,
|
type: metric.type,
|
||||||
name: metric.name,
|
name: metric.name,
|
||||||
|
level: metric.level,
|
||||||
|
components: metric.components,
|
||||||
sensor: metric.sensor,
|
sensor: metric.sensor,
|
||||||
config: metric.config,
|
config: metric.config,
|
||||||
isWindowInputRaw: metric.isWindowInputRaw,
|
|
||||||
inputRaw: {
|
|
||||||
type: metric.inputRaw?.type ?? "all",
|
|
||||||
interval: metric.inputRaw?.interval ?? 30,
|
|
||||||
unit: metric.inputRaw?.unit ?? "sec"
|
|
||||||
},
|
|
||||||
isWindowOutputRaw: metric.isWindowOutputRaw,
|
isWindowOutputRaw: metric.isWindowOutputRaw,
|
||||||
outputRaw: {
|
outputRaw: {
|
||||||
type: metric.outputRaw?.type ?? "all",
|
type: metric.outputRaw?.type ?? "all",
|
||||||
@ -137,6 +134,11 @@ export default {
|
|||||||
},
|
},
|
||||||
async deployApplication(uuid: string): Promise<DeployResponseType> {
|
async deployApplication(uuid: string): Promise<DeployResponseType> {
|
||||||
return axios.post(`/api/v1/application/${uuid}/uuid/deploy`).then(({data}) => data)
|
return axios.post(`/api/v1/application/${uuid}/uuid/deploy`).then(({data}) => data)
|
||||||
|
},
|
||||||
|
async publishPolicies(policies:string): Promise<PolicyResponseType> {
|
||||||
|
console.log("Publishing policies" , policies)
|
||||||
|
return axios.post(`/api/v1/policies/publish`,{policies:policies}).then(({data}) => data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import { IResource } from "@/interfaces/resources.interface.ts"
|
import {INodeCandidate, IResource} from "@/interfaces/resources.interface.ts"
|
||||||
import { IResourcePayload } from "@/types/resource.ts"
|
import { IResourcePayload } from "@/types/resource.ts"
|
||||||
import { DeleteResponseType } from "@/types/responses.ts"
|
import { DeleteResponseType } from "@/types/responses.ts"
|
||||||
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getAllResources(): Promise<IPagination<IResource>> {
|
async getAllResources(): Promise<IPagination<IResource>> {
|
||||||
return axios.get("/api/v1/resources").then(({ data }) => data)
|
return axios.get("/api/v1/resources/all").then(({ data }) => data)
|
||||||
},
|
},
|
||||||
|
async getCandidates(uuid:string): Promise<Array<INodeCandidate>> {
|
||||||
|
return axios.get(`/api/v1/resources/${uuid}/candidates`).then(({ data }) => data)
|
||||||
|
},
|
||||||
|
|
||||||
async createResource(payload: IResourcePayload): Promise<IResource> {
|
async createResource(payload: IResourcePayload): Promise<IResource> {
|
||||||
|
|
||||||
return axios.post("/api/v1/resources", payload).then(({ data }) => data)
|
return axios.post("/api/v1/resources", payload).then(({ data }) => data)
|
||||||
},
|
},
|
||||||
async editResource(uuid: string, payload: IResourcePayload): Promise<IResource> {
|
async editResource(uuid: string, payload: IResourcePayload): Promise<IResource> {
|
||||||
|
@ -30,6 +30,12 @@ export const useSideMenuStore = defineStore("sideMenu", {
|
|||||||
pageName: "applications-resources",
|
pageName: "applications-resources",
|
||||||
title: "Resources"
|
title: "Resources"
|
||||||
}
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
pageName: "policy-editor",
|
||||||
|
title: "Security Policies"
|
||||||
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
24
gui/src/store/modules/policies.ts
Normal file
24
gui/src/store/modules/policies.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from "pinia"
|
||||||
|
import { IResource, INodeCandidate } from "@/interfaces/resources.interface.ts"
|
||||||
|
|
||||||
|
import resourceService from "@/store/api-services/resources.service.ts"
|
||||||
|
import { IResourcePayload } from "@/types/resource.ts"
|
||||||
|
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
||||||
|
import applicationService from "@/store/api-services/application.service.ts";
|
||||||
|
|
||||||
|
interface PoliciesState {
|
||||||
|
rules: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePolicyStore = defineStore("policies", {
|
||||||
|
state: (): PoliciesState => ({
|
||||||
|
rules: ""
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
async publishPolicies(rules:string): Promise<string> {
|
||||||
|
return applicationService.publishPolicies(rules).then((status) => {
|
||||||
|
return status.status
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
@ -1,29 +1,39 @@
|
|||||||
import { defineStore } from "pinia"
|
import { defineStore } from "pinia"
|
||||||
import { IResource } from "@/interfaces/resources.interface.ts"
|
import { IResource, INodeCandidate } from "@/interfaces/resources.interface.ts"
|
||||||
|
|
||||||
import resourceService from "@/store/api-services/resources.service.ts"
|
import resourceService from "@/store/api-services/resources.service.ts"
|
||||||
import { IResourcePayload } from "@/types/resource.ts"
|
import { IResourcePayload } from "@/types/resource.ts"
|
||||||
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
import { IPlatform } from "@/interfaces/platform.interface.ts"
|
||||||
|
|
||||||
interface ResourcesState {
|
interface ResourcesState {
|
||||||
resources: IPagination<IResource>
|
resources: IPagination<IResource>
|
||||||
|
candidates: Array<INodeCandidate>
|
||||||
platforms: Array<IPlatform>
|
platforms: Array<IPlatform>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useResourceStore = defineStore("resource", {
|
export const useResourceStore = defineStore("resource", {
|
||||||
state: (): ResourcesState => ({
|
state: (): ResourcesState => ({
|
||||||
resources: { pages: 0, currentPage: 0, results: [] },
|
resources: { pages: 0, currentPage: 0, results: [] },
|
||||||
|
candidates: [],
|
||||||
platforms: []
|
platforms: []
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async createResource(payload: IResourcePayload): Promise<IResource> {
|
async createResource(payload: IResourcePayload): Promise<IResource> {
|
||||||
const createdResource = await resourceService.createResource(payload)
|
const createdResource = await resourceService.createResource(payload)
|
||||||
|
createdResource.platform = {'uuid':createdResource._platform[0].uuid, 'title':createdResource._platform[0].title}
|
||||||
this.resources.results.unshift(createdResource)
|
this.resources.results.unshift(createdResource)
|
||||||
return createdResource
|
return createdResource
|
||||||
},
|
},
|
||||||
async getAllResources(): Promise<IPagination<IResource>> {
|
async getAllResources(): Promise<IPagination<IResource>> {
|
||||||
|
this.platforms = await this.getPlatforms()
|
||||||
this.resources = await resourceService.getAllResources()
|
this.resources = await resourceService.getAllResources()
|
||||||
return this.resources
|
return this.resources
|
||||||
},
|
},
|
||||||
|
async getAllNodeCandidate(uuid:string): Promise<Array<INodeCandidate>> {
|
||||||
|
this.candidates = await resourceService.getCandidates(uuid)
|
||||||
|
return this.candidates
|
||||||
|
},
|
||||||
|
|
||||||
async deleteResource(uuid: string): Promise<IPagination<IResource>> {
|
async deleteResource(uuid: string): Promise<IPagination<IResource>> {
|
||||||
return await resourceService.deleteResource(uuid).then(() => {
|
return await resourceService.deleteResource(uuid).then(() => {
|
||||||
const removedResourceIndex = this.resources.results.findIndex((res) => res.uuid === uuid)
|
const removedResourceIndex = this.resources.results.findIndex((res) => res.uuid === uuid)
|
||||||
|
@ -42,6 +42,7 @@ export const useUIStore = defineStore("ui", {
|
|||||||
controlledWindowClosure: true,
|
controlledWindowClosure: true,
|
||||||
isConfirmPresent: true,
|
isConfirmPresent: true,
|
||||||
confirmAction: () => {
|
confirmAction: () => {
|
||||||
|
console.log("Confirm action")
|
||||||
this.openedModalWindow = null
|
this.openedModalWindow = null
|
||||||
this.setSnackbarMessage()
|
this.setSnackbarMessage()
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export type MetricType = "raw" | "composite"
|
export type MetricType = "raw" | "composite"
|
||||||
export type BehaviorType = "all" | "sliding"
|
export type BehaviorType = "all" | "sliding" | "batch" | "first" | "last"
|
||||||
export type UnitTimeType = "ms" | "sec" | "min" | "hour" | "day"
|
export type UnitTimeType = "ms" | "sec" | "min" | "hour" | "day"
|
||||||
export type RawMetricConfigType = { name: string; value: string }
|
export type RawMetricConfigType = { name: string; value: string }
|
||||||
export type OperatorType = ">" | "<" | "<=" | ">=" | "==" | "!=="
|
export type OperatorType = ">" | "<" | "<=" | ">=" | "==" | "!=="
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
import { IResource } from "@/interfaces/resources.interface.ts"
|
import {INodeCandidate, IResource} from "@/interfaces/resources.interface.ts"
|
||||||
|
|
||||||
export type IResourcePayload = Omit<IResource, "uuid" | "enabled">
|
export type IResourcePayload = Omit<IResource, "uuid" | "enabled">
|
||||||
|
export type ICandidatesPayload = Omit<INodeCandidate, "uuid" | "enabled">
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export type DeleteResponseType = { status: "success"; message: string }
|
export type DeleteResponseType = { status: "success"; message: string }
|
||||||
export type DeployResponseType = { status: "success"; message: string }
|
export type DeployResponseType = { status: "success"; message: string }
|
||||||
|
export type PolicyResponseType = { status: "success"; message: string }
|
||||||
|
@ -54,6 +54,9 @@ const getColor = (colorKey: DotNestedKeys<Colors>, opacity: number = 1) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const generateColor = (experimental: string): string => {
|
const generateColor = (experimental: string): string => {
|
||||||
|
if(!experimental){
|
||||||
|
return PLATFORM_COLOR['bg-indigo-600']
|
||||||
|
}
|
||||||
const colorKey = [...experimental].reduce((acc, char) => acc + char.charCodeAt(0), 0) % PLATFORM_COLOR.length
|
const colorKey = [...experimental].reduce((acc, char) => acc + char.charCodeAt(0), 0) % PLATFORM_COLOR.length
|
||||||
return PLATFORM_COLOR[colorKey]
|
return PLATFORM_COLOR[colorKey]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user