feat: add kaizen indicator

This commit is contained in:
Julien Calixte
2025-08-10 13:08:36 +02:00
parent a9b6ce17f1
commit 1916c5ee4d
4 changed files with 86 additions and 35 deletions

View File

@@ -17,6 +17,7 @@
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"@vueuse/core": "^12.2.0", "@vueuse/core": "^12.2.0",
"chart.js": "^4.5.0",
"chart.xkcd": "^1.1.15", "chart.xkcd": "^1.1.15",
"comlink": "^4.4.2", "comlink": "^4.4.2",
"daisyui": "^5.0.50", "daisyui": "^5.0.50",
@@ -26,6 +27,7 @@
"random-js": "^2.1.0", "random-js": "^2.1.0",
"tailwindcss": "^4.1.11", "tailwindcss": "^4.1.11",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-chartjs": "^5.3.2",
"vue-starport": "^0.4.0" "vue-starport": "^0.4.0"
}, },
"devDependencies": { "devDependencies": {

30
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ importers:
'@vueuse/core': '@vueuse/core':
specifier: ^12.2.0 specifier: ^12.2.0
version: 12.2.0(typescript@5.7.2) version: 12.2.0(typescript@5.7.2)
chart.js:
specifier: ^4.5.0
version: 4.5.0
chart.xkcd: chart.xkcd:
specifier: ^1.1.15 specifier: ^1.1.15
version: 1.1.15 version: 1.1.15
@@ -41,6 +44,9 @@ importers:
vue: vue:
specifier: ^3.5.13 specifier: ^3.5.13
version: 3.5.13(typescript@5.7.2) version: 3.5.13(typescript@5.7.2)
vue-chartjs:
specifier: ^5.3.2
version: 5.3.2(chart.js@4.5.0)(vue@3.5.13(typescript@5.7.2))
vue-starport: vue-starport:
specifier: ^0.4.0 specifier: ^0.4.0
version: 0.4.0(typescript@5.7.2) version: 0.4.0(typescript@5.7.2)
@@ -408,6 +414,9 @@ packages:
'@jridgewell/trace-mapping@0.3.29': '@jridgewell/trace-mapping@0.3.29':
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
'@kurkle/color@0.3.4':
resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==}
'@parcel/watcher-android-arm64@2.5.1': '@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
@@ -889,6 +898,10 @@ packages:
resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==}
engines: {node: '>=12'} engines: {node: '>=12'}
chart.js@4.5.0:
resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==}
engines: {pnpm: '>=8'}
chart.xkcd@1.1.15: chart.xkcd@1.1.15:
resolution: {integrity: sha512-FPpNCkaVSPyB6GIb9eXKEAjKSnr6hA7blzQFUeTkZKvSr9wcg1eSK73V6APgfrzkDDK7X+iVtLXJXIGPrCFj8g==} resolution: {integrity: sha512-FPpNCkaVSPyB6GIb9eXKEAjKSnr6hA7blzQFUeTkZKvSr9wcg1eSK73V6APgfrzkDDK7X+iVtLXJXIGPrCFj8g==}
@@ -1387,6 +1400,12 @@ packages:
jsdom: jsdom:
optional: true optional: true
vue-chartjs@5.3.2:
resolution: {integrity: sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==}
peerDependencies:
chart.js: ^4.1.1
vue: ^3.0.0-0 || ^2.7.0
vue-demi@0.14.10: vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -1602,6 +1621,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
'@kurkle/color@0.3.4': {}
'@parcel/watcher-android-arm64@2.5.1': '@parcel/watcher-android-arm64@2.5.1':
optional: true optional: true
@@ -2020,6 +2041,10 @@ snapshots:
loupe: 3.1.3 loupe: 3.1.3
pathval: 2.0.0 pathval: 2.0.0
chart.js@4.5.0:
dependencies:
'@kurkle/color': 0.3.4
chart.xkcd@1.1.15: chart.xkcd@1.1.15:
dependencies: dependencies:
d3-axis: 1.0.12 d3-axis: 1.0.12
@@ -2507,6 +2532,11 @@ snapshots:
- supports-color - supports-color
- terser - terser
vue-chartjs@5.3.2(chart.js@4.5.0)(vue@3.5.13(typescript@5.7.2)):
dependencies:
chart.js: 4.5.0
vue: 3.5.13(typescript@5.7.2)
vue-demi@0.14.10(vue@3.5.13(typescript@5.7.2)): vue-demi@0.14.10(vue@3.5.13(typescript@5.7.2)):
dependencies: dependencies:
vue: 3.5.13(typescript@5.7.2) vue: 3.5.13(typescript@5.7.2)

View File

@@ -1,8 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { Chart as ChartJS, registerables } from 'chart.js'
import { useBoardGameStore } from '@/modules/5s/board-game-store' import { useBoardGameStore } from '@/modules/5s/board-game-store'
import { toDuration, toSeconds } from '@/modules/5s/utils' import { toDuration, toSeconds } from '@/modules/5s/utils'
import { getNatural } from '@/utils' import { getNatural } from '@/utils'
import { _ } from '@faker-js/faker/dist/airline-D6ksJFwG'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { Bar } from 'vue-chartjs'
ChartJS.register(...registerables)
const boardGameStore = useBoardGameStore() const boardGameStore = useBoardGameStore()
@@ -29,33 +34,52 @@ setInterval(() => {
<template v-if="boardGameStore.meta.perfs.length > 0"> <template v-if="boardGameStore.meta.perfs.length > 0">
<h3>Last performances</h3> <h3>Last performances</h3>
<table class="table"> <div class="overflow-x-auto">
<thead> <table class="table">
<tr> <thead>
<th>Duration</th> <tr>
<th>Board Games</th> <th>Duration</th>
<th>Time / board game</th> <th>Board Games</th>
</tr> <th>Time / board game</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="perf in last10Perfs"> <tbody>
<td class="numeric"> <tr v-for="perf in last10Perfs">
{{ toDuration(new Date(perf.start), new Date(perf.end)) }} <td class="numeric">
</td> {{ toDuration(new Date(perf.start), new Date(perf.end)) }}
<td class="numeric"> </td>
{{ perf.totalGames }} <td class="numeric">
</td> {{ perf.totalGames }}
<td class="numeric"> </td>
{{ <td class="numeric">
getNatural( {{
toSeconds(new Date(perf.start), new Date(perf.end)), getNatural(
perf.totalGames toSeconds(new Date(perf.start), new Date(perf.end)),
) perf.totalGames
}}s )
</td> }}s
</tr> </td>
</tbody> </tr>
</table> </tbody>
</table>
</div>
<h3>Progression</h3>
<Bar
id="my-chart-id"
:data="{
labels: boardGameStore.meta.perfs.map((_, i) => `Round #${i + 1}`),
datasets: [
{
label: 'Time per board game (in s)',
data: boardGameStore.meta.perfs.map((perf) =>
toSeconds(new Date(perf.start), new Date(perf.end))
)
}
]
}"
/>
</template> </template>
</div> </div>
</template> </template>

View File

@@ -91,11 +91,6 @@ const submit = () => {
{{ part.name }} {{ part.name }}
</span> </span>
<template v-if="partIndex === boardGameStore.currentPartIndex"> <template v-if="partIndex === boardGameStore.currentPartIndex">
<div class="inline-grid *:[grid-area:1/1]">
<div class="status status-primary animate-ping"></div>
<div class="status status-primary"></div>
</div>
<ol> <ol>
<li <li
v-for="(task, taskIndex) in boardGameStore.currentPart v-for="(task, taskIndex) in boardGameStore.currentPart
@@ -116,9 +111,9 @@ const submit = () => {
boardGameStore.currentTask boardGameStore.currentTask
" "
> >
<div class="inline-grid *:[grid-area:1/1]"> <div class="inline-grid *:[grid-area:1/1] ml-2">
<div class="status status-primary animate-ping"></div> <div class="status status-info animate-ping"></div>
<div class="status status-primary"></div> <div class="status status-info"></div>
</div> </div>
<ul> <ul>
<li <li