From 38f6f0c20ec1774fa9bb4728b1564a95cda645d7 Mon Sep 17 00:00:00 2001 From: mlbonhomme <bonhomme@teklia.com> Date: Thu, 23 Jan 2025 12:23:46 +0100 Subject: [PATCH 1/4] Show worker costs --- src/components/Process/Workers/Costs.vue | 46 +++++++++++++++++++ .../Process/Workers/WorkerRuns/WorkerTag.vue | 14 ++++-- src/types/worker.ts | 3 ++ src/views/Process/Workers/List.vue | 8 +++- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/components/Process/Workers/Costs.vue diff --git a/src/components/Process/Workers/Costs.vue b/src/components/Process/Workers/Costs.vue new file mode 100644 index 000000000..3320d92d7 --- /dev/null +++ b/src/components/Process/Workers/Costs.vue @@ -0,0 +1,46 @@ +<template> + <div class="field is-grouped is-grouped-multiline mt-3"> + <div class="control"> + <div class="tags has-addons"> + <span class="tag is-medium is-light">CPU</span> + <span class="tag is-medium" :class="priceTagColor(worker.cost_cpu_hour)">{{ worker.cost_cpu_hour }}</span> + <span class="tag is-medium is-light">€ / h</span> + </div> + </div> + + <div class="control"> + <div class="tags has-addons"> + <span class="tag is-medium is-light">GPU</span> + <span class="tag is-medium" :class="priceTagColor(worker.cost_gpu_hour)">{{ worker.cost_gpu_hour }}</span> + <span class="tag is-medium is-light">€ / h</span> + </div> + </div> + + <div class="control"> + <div class="tags has-addons"> + <span class="tag is-medium" :class="priceTagColor(worker.cost_1k_elements)">{{ worker.cost_1k_elements }}</span> + <span class="tag is-medium is-light">€ / 1000 elements</span> + </div> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent, PropType } from 'vue' +import { Worker } from '@/types/worker' + +export default defineComponent({ + props: { + worker: { + type: Object as PropType<Worker>, + required: true + } + }, + methods: { + priceTagColor (value: number) { + if (value > 0) return 'is-warning' + return 'is-info is-light' + } + } +}) +</script> diff --git a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue index 79efa8cdc..a6a609d51 100644 --- a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue +++ b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue @@ -9,16 +9,19 @@ <span class="mx-1" :title="worker.name"> {{ worker.name }} </span> + <span v-if="hasCost" class="tag is-warning">€</span> </template> -<script> +<script lang="ts"> +import { defineComponent, PropType } from 'vue' import { WORKER_TYPE_COLORS } from '@/config' +import { Worker } from '@/types/worker' -export default { +export default defineComponent({ props: { // A worker instance to build base tag elements worker: { - type: Object, + type: Object as PropType<Worker>, required: true } }, @@ -28,7 +31,10 @@ export default { }, workerClass () { return WORKER_TYPE_COLORS[this.workerType]?.cssClass ?? WORKER_TYPE_COLORS.default.cssClass + }, + hasCost () { + return this.worker.cost_gpu_hour | this.worker.cost_cpu_hour | this.worker.cost_1k_elements } } -} +}) </script> diff --git a/src/types/worker.ts b/src/types/worker.ts index aefe81d9d..7724c0baa 100644 --- a/src/types/worker.ts +++ b/src/types/worker.ts @@ -16,6 +16,9 @@ export interface Worker { description: string repository_url: string | null archived: boolean + cost_cpu_hour: number + cost_gpu_hour: number + cost_1k_elements: number } export type UserConfiguration = Record<string, UserConfigurationField> diff --git a/src/views/Process/Workers/List.vue b/src/views/Process/Workers/List.vue index 0a7346164..201c526ca 100644 --- a/src/views/Process/Workers/List.vue +++ b/src/views/Process/Workers/List.vue @@ -108,6 +108,7 @@ <WorkerTag :worker="selectedWorker" /> </div> </h2> + <WorkerCosts v-if="hasCosts" :worker="selectedWorker" /> <ItemId label="Worker ID:" :item-id="selectedWorker.id" /> <div class="field mt-2"> <label class="label">Description</label> @@ -173,6 +174,7 @@ import WorkerTag from '@/components/Process/Workers/WorkerRuns/WorkerTag' import CreateForm from '@/components/Process/Workers/CreateForm.vue' import ItemId from '@/components/ItemId.vue' import ArchivalModal from '@/components/ArchivalModal.vue' +import WorkerCosts from '@/components/Process/Workers/Costs.vue' export default { components: { @@ -182,7 +184,8 @@ export default { WorkerTag, CreateForm, ItemId, - ArchivalModal + ArchivalModal, + WorkerCosts }, mixins: [ truncateMixin @@ -247,6 +250,9 @@ export default { }, canArchive () { return (this.user.is_admin || this.user.can_manage_workers) + }, + hasCosts () { + return this.selectedWorker.cost_gpu_hour | this.selectedWorker.cost_cpu_hour | this.selectedWorker.cost_1k_elements } }, methods: { -- GitLab From e2a31561798ad19f3866fbf101251803751b8a50 Mon Sep 17 00:00:00 2001 From: mlbonhomme <bonhomme@teklia.com> Date: Thu, 23 Jan 2025 16:12:22 +0100 Subject: [PATCH 2/4] costs are string --- src/components/Process/Workers/Costs.vue | 4 ++-- src/components/Process/Workers/WorkerRuns/WorkerTag.vue | 2 +- src/types/worker.ts | 6 +++--- src/views/Process/Workers/List.vue | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/Process/Workers/Costs.vue b/src/components/Process/Workers/Costs.vue index 3320d92d7..a39a33fa0 100644 --- a/src/components/Process/Workers/Costs.vue +++ b/src/components/Process/Workers/Costs.vue @@ -37,8 +37,8 @@ export default defineComponent({ } }, methods: { - priceTagColor (value: number) { - if (value > 0) return 'is-warning' + priceTagColor (value: string) { + if (parseFloat(value) > 0) return 'is-warning' return 'is-info is-light' } } diff --git a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue index a6a609d51..a48788b0b 100644 --- a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue +++ b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue @@ -33,7 +33,7 @@ export default defineComponent({ return WORKER_TYPE_COLORS[this.workerType]?.cssClass ?? WORKER_TYPE_COLORS.default.cssClass }, hasCost () { - return this.worker.cost_gpu_hour | this.worker.cost_cpu_hour | this.worker.cost_1k_elements + return parseFloat(this.worker.cost_gpu_hour) > 0 || parseFloat(this.worker.cost_cpu_hour) > 0 || parseFloat(this.worker.cost_1k_elements) > 0 } } }) diff --git a/src/types/worker.ts b/src/types/worker.ts index 7724c0baa..603c6c12c 100644 --- a/src/types/worker.ts +++ b/src/types/worker.ts @@ -16,9 +16,9 @@ export interface Worker { description: string repository_url: string | null archived: boolean - cost_cpu_hour: number - cost_gpu_hour: number - cost_1k_elements: number + cost_cpu_hour: string + cost_gpu_hour: string + cost_1k_elements: string } export type UserConfiguration = Record<string, UserConfigurationField> diff --git a/src/views/Process/Workers/List.vue b/src/views/Process/Workers/List.vue index 201c526ca..d0ec03148 100644 --- a/src/views/Process/Workers/List.vue +++ b/src/views/Process/Workers/List.vue @@ -252,7 +252,7 @@ export default { return (this.user.is_admin || this.user.can_manage_workers) }, hasCosts () { - return this.selectedWorker.cost_gpu_hour | this.selectedWorker.cost_cpu_hour | this.selectedWorker.cost_1k_elements + return parseFloat(this.selectedWorker.cost_gpu_hour) > 0 || parseFloat(this.selectedWorker.cost_cpu_hour) > 0 || parseFloat(this.selectedWorker.cost_1k_elements) > 0 } }, methods: { -- GitLab From f0a688937f4fa37b1f6f89f0eda6b5da2bbfef08 Mon Sep 17 00:00:00 2001 From: mlbonhomme <bonhomme@teklia.com> Date: Thu, 23 Jan 2025 18:13:04 +0100 Subject: [PATCH 3/4] add hasCosts helper + add costs to worker details view --- .../Process/Workers/WorkerRuns/WorkerTag.vue | 9 +++++---- src/helpers/worker.ts | 5 +++++ src/views/Process/Workers/List.vue | 9 ++++----- src/views/Process/Workers/Manage.vue | 10 ++++++++-- 4 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 src/helpers/worker.ts diff --git a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue index a48788b0b..51d05fa99 100644 --- a/src/components/Process/Workers/WorkerRuns/WorkerTag.vue +++ b/src/components/Process/Workers/WorkerRuns/WorkerTag.vue @@ -9,13 +9,14 @@ <span class="mx-1" :title="worker.name"> {{ worker.name }} </span> - <span v-if="hasCost" class="tag is-warning">€</span> + <span v-if="hasCosts(worker)" class="tag is-warning">€</span> </template> <script lang="ts"> import { defineComponent, PropType } from 'vue' import { WORKER_TYPE_COLORS } from '@/config' import { Worker } from '@/types/worker' +import { hasCosts } from '@/helpers/worker' export default defineComponent({ props: { @@ -25,15 +26,15 @@ export default defineComponent({ required: true } }, + data: () => ({ + hasCosts + }), computed: { workerType () { return this.worker?.type }, workerClass () { return WORKER_TYPE_COLORS[this.workerType]?.cssClass ?? WORKER_TYPE_COLORS.default.cssClass - }, - hasCost () { - return parseFloat(this.worker.cost_gpu_hour) > 0 || parseFloat(this.worker.cost_cpu_hour) > 0 || parseFloat(this.worker.cost_1k_elements) > 0 } } }) diff --git a/src/helpers/worker.ts b/src/helpers/worker.ts new file mode 100644 index 000000000..0ded2ceff --- /dev/null +++ b/src/helpers/worker.ts @@ -0,0 +1,5 @@ +import { Worker } from "@/types/worker" + +export const hasCosts = (worker: Worker) => { + return parseFloat(worker.cost_gpu_hour) > 0 || parseFloat(worker.cost_cpu_hour) > 0 || parseFloat(worker.cost_1k_elements) > 0 +} \ No newline at end of file diff --git a/src/views/Process/Workers/List.vue b/src/views/Process/Workers/List.vue index d0ec03148..a137d6652 100644 --- a/src/views/Process/Workers/List.vue +++ b/src/views/Process/Workers/List.vue @@ -108,7 +108,7 @@ <WorkerTag :worker="selectedWorker" /> </div> </h2> - <WorkerCosts v-if="hasCosts" :worker="selectedWorker" /> + <WorkerCosts v-if="hasCosts(selectedWorker)" :worker="selectedWorker" /> <ItemId label="Worker ID:" :item-id="selectedWorker.id" /> <div class="field mt-2"> <label class="label">Description</label> @@ -175,6 +175,7 @@ import CreateForm from '@/components/Process/Workers/CreateForm.vue' import ItemId from '@/components/ItemId.vue' import ArchivalModal from '@/components/ArchivalModal.vue' import WorkerCosts from '@/components/Process/Workers/Costs.vue' +import { hasCosts } from '@/helpers/worker' export default { components: { @@ -238,7 +239,8 @@ export default { archiveModal: false, archivedWorkers: false, md: new MarkdownIt({ breaks: true }), - expandDescription: false + expandDescription: false, + hasCosts }), computed: { ...mapState(useWorkerStore, ['workerTypes']), @@ -250,9 +252,6 @@ export default { }, canArchive () { return (this.user.is_admin || this.user.can_manage_workers) - }, - hasCosts () { - return parseFloat(this.selectedWorker.cost_gpu_hour) > 0 || parseFloat(this.selectedWorker.cost_cpu_hour) > 0 || parseFloat(this.selectedWorker.cost_1k_elements) > 0 } }, methods: { diff --git a/src/views/Process/Workers/Manage.vue b/src/views/Process/Workers/Manage.vue index 4696fc4e9..08c0462c5 100644 --- a/src/views/Process/Workers/Manage.vue +++ b/src/views/Process/Workers/Manage.vue @@ -23,6 +23,8 @@ </button> </div> + <WorkerCosts v-if="hasCosts(worker)" :worker="worker" /> + <div class="field"> <label class="label">Description</label> <div class="control"> @@ -74,6 +76,7 @@ import { mapState, mapActions } from 'pinia' import { defineComponent } from 'vue' import { mapGetters as mapVuexGetters, mapState as mapVuexState } from 'vuex' import { errorParser } from '@/helpers' +import { hasCosts } from '@/helpers/worker' import VersionList from '@/components/Process/Workers/Versions/List.vue' import ListMembers from '@/components/Memberships/ListMembers.vue' import { useNotificationStore, useWorkerStore } from '@/stores' @@ -81,6 +84,7 @@ import ItemId from '@/components/ItemId.vue' import ArchivalModal from '@/components/ArchivalModal.vue' import EditForm from '@/components/Process/Workers/EditForm.vue' import WorkerTag from '@/components/Process/Workers/WorkerRuns/WorkerTag.vue' +import WorkerCosts from '@/components/Process/Workers/Costs.vue' export default defineComponent({ props: { @@ -95,13 +99,15 @@ export default defineComponent({ ItemId, ArchivalModal, EditForm, - WorkerTag + WorkerTag, + WorkerCosts }, data: () => ({ loading: false, error: null as string | null, archiveModal: false, - md: new MarkdownIt({ breaks: true }) + md: new MarkdownIt({ breaks: true }), + hasCosts }), async created () { if (!this.worker) await this.retrieveWorker() -- GitLab From 00cac2280fa0082cd5c2ee0c35f4cdfc23c6de3f Mon Sep 17 00:00:00 2001 From: Erwan Rouchet <rouchet@teklia.com> Date: Mon, 27 Jan 2025 11:55:48 +0100 Subject: [PATCH 4/4] Explicit typing and VSCode linting errors --- src/helpers/worker.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/worker.ts b/src/helpers/worker.ts index 0ded2ceff..3fbc85417 100644 --- a/src/helpers/worker.ts +++ b/src/helpers/worker.ts @@ -1,5 +1,5 @@ -import { Worker } from "@/types/worker" +import { Worker } from '@/types/worker' -export const hasCosts = (worker: Worker) => { - return parseFloat(worker.cost_gpu_hour) > 0 || parseFloat(worker.cost_cpu_hour) > 0 || parseFloat(worker.cost_1k_elements) > 0 -} \ No newline at end of file +export const hasCosts = (worker: Worker): boolean => { + return parseFloat(worker.cost_gpu_hour) > 0 || parseFloat(worker.cost_cpu_hour) > 0 || parseFloat(worker.cost_1k_elements) > 0 +} -- GitLab