@vue-skuilder/common-ui 0.2.34 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ import { ECElementEvent, EChartsCoreOption } from 'echarts/core';
2
+ type __VLS_Props = {
3
+ option: EChartsCoreOption;
4
+ height: number;
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
7
+ click: (event: ECElementEvent) => any;
8
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onClick?: ((event: ECElementEvent) => any) | undefined;
10
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
11
+ el: HTMLDivElement;
12
+ }, HTMLDivElement>;
13
+ export default _default;
14
+ //# sourceMappingURL=EChart.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EChart.vue.d.ts","sourceRoot":"","sources":["../../../src/admin/components/EChart.vue"],"names":[],"mappings":"AA8DA,OAAO,EAAa,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAoB,MAAM,cAAc,CAAC;AA2BxG,KAAK,WAAW,GAAG;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;;;;;;;;AAsEjE,wBASG"}
@@ -1,9 +1,9 @@
1
1
  import { DiagnosticsInterpreters, LearnerDataset } from '@vue-skuilder/db/diagnostics';
2
2
  /**
3
- * One learner: sessions (list, then a session's detail), card history, and,
3
+ * One learner: sessions (list, then a session's detail), card history,
4
4
  * when the dataset carries the course's strategy docs, the pipeline with this
5
- * learner's run stats. Session timelines link into card history. Navigation is internal;
6
- * hosts that want URLs can compose the three views themselves.
5
+ * learner's run stats, and per-tag ELO. Session timelines link into card history. Navigation is internal;
6
+ * hosts that want URLs can compose the views themselves.
7
7
  */
8
8
  type __VLS_Props = {
9
9
  dataset: LearnerDataset;
@@ -1 +1 @@
1
- {"version":3,"file":"LearnerDiagnostics.vue.d.ts","sourceRoot":"","sources":["../../../src/admin/components/LearnerDiagnostics.vue"],"names":[],"mappings":"AAwFA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnH;;;;;GAKG;AACH,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC,CAAC;;AAmOF,wBAOG"}
1
+ {"version":3,"file":"LearnerDiagnostics.vue.d.ts","sourceRoot":"","sources":["../../../src/admin/components/LearnerDiagnostics.vue"],"names":[],"mappings":"AA4FA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAOnH;;;;;GAKG;AACH,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC,CAAC;;AA4PF,wBAOG"}
@@ -0,0 +1,14 @@
1
+ import { DiagnosticsInterpreters, LearnerDataset } from '@vue-skuilder/db/diagnostics';
2
+ /**
3
+ * A learner's per-tag ELO: which skills they're rated high or low on, how
4
+ * much evidence each rating rests on, and how ratings moved. Filtered by tag
5
+ * batch: the namespace × role groups found on the tags, plus any the course
6
+ * names (`interpreters.tagBatches`).
7
+ */
8
+ type __VLS_Props = {
9
+ dataset: LearnerDataset;
10
+ interpreters?: DiagnosticsInterpreters;
11
+ };
12
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
13
+ export default _default;
14
+ //# sourceMappingURL=LearnerTagElo.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LearnerTagElo.vue.d.ts","sourceRoot":"","sources":["../../../src/admin/components/LearnerTagElo.vue"],"names":[],"mappings":"AAwjBA,OAAO,EAIL,KAAK,uBAAuB,EAE5B,KAAK,cAAc,EAGpB,MAAM,8BAA8B,CAAC;AAItC;;;;;GAKG;AACH,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC,CAAC;;AAo7BF,wBAOG"}
@@ -20,4 +20,5 @@ export { default as LearnerCardHistory } from './components/LearnerCardHistory.v
20
20
  export { default as CardDossierDetail } from './components/CardDossierDetail.vue';
21
21
  export { default as RunDetail } from './components/RunDetail.vue';
22
22
  export { default as PipelineOverview } from './components/PipelineOverview.vue';
23
+ export { default as LearnerTagElo } from './components/LearnerTagElo.vue';
23
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,gCAAgC,CAAC"}
@@ -297,7 +297,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
297
297
  readonly required: false;
298
298
  readonly default: "";
299
299
  };
300
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("first" | "prev" | "next" | "last" | "set-page")[], "first" | "prev" | "next" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
300
+ }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("next" | "prev" | "first" | "last" | "set-page")[], "next" | "prev" | "first" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
301
301
  readonly pages: {
302
302
  readonly type: PropType<number[]>;
303
303
  readonly required: true;
@@ -317,9 +317,9 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
317
317
  readonly default: "";
318
318
  };
319
319
  }>> & Readonly<{
320
- onFirst?: ((...args: any[]) => any) | undefined;
321
- onPrev?: ((...args: any[]) => any) | undefined;
322
320
  onNext?: ((...args: any[]) => any) | undefined;
321
+ onPrev?: ((...args: any[]) => any) | undefined;
322
+ onFirst?: ((...args: any[]) => any) | undefined;
323
323
  onLast?: ((...args: any[]) => any) | undefined;
324
324
  "onSet-page"?: ((...args: any[]) => any) | undefined;
325
325
  }>, {
@@ -341,7 +341,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
341
341
  readonly required: false;
342
342
  readonly default: "";
343
343
  };
344
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("first" | "prev" | "next" | "last" | "set-page")[], "first" | "prev" | "next" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
344
+ }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("next" | "prev" | "first" | "last" | "set-page")[], "next" | "prev" | "first" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
345
345
  readonly pages: {
346
346
  readonly type: PropType<number[]>;
347
347
  readonly required: true;
@@ -361,9 +361,9 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
361
361
  readonly default: "";
362
362
  };
363
363
  }>> & Readonly<{
364
- onFirst?: ((...args: any[]) => any) | undefined;
365
- onPrev?: ((...args: any[]) => any) | undefined;
366
364
  onNext?: ((...args: any[]) => any) | undefined;
365
+ onPrev?: ((...args: any[]) => any) | undefined;
366
+ onFirst?: ((...args: any[]) => any) | undefined;
367
367
  onLast?: ((...args: any[]) => any) | undefined;
368
368
  "onSet-page"?: ((...args: any[]) => any) | undefined;
369
369
  }>, {
@@ -18,7 +18,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
18
18
  readonly required: false;
19
19
  readonly default: "";
20
20
  };
21
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("first" | "prev" | "next" | "last" | "set-page")[], "first" | "prev" | "next" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
21
+ }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("next" | "prev" | "first" | "last" | "set-page")[], "next" | "prev" | "first" | "last" | "set-page", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
22
22
  readonly pages: {
23
23
  readonly type: PropType<number[]>;
24
24
  readonly required: true;
@@ -38,9 +38,9 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
38
38
  readonly default: "";
39
39
  };
40
40
  }>> & Readonly<{
41
- onFirst?: ((...args: any[]) => any) | undefined;
42
- onPrev?: ((...args: any[]) => any) | undefined;
43
41
  onNext?: ((...args: any[]) => any) | undefined;
42
+ onPrev?: ((...args: any[]) => any) | undefined;
43
+ onFirst?: ((...args: any[]) => any) | undefined;
44
44
  onLast?: ((...args: any[]) => any) | undefined;
45
45
  "onSet-page"?: ((...args: any[]) => any) | undefined;
46
46
  }>, {
@@ -59,7 +59,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
59
59
  showTooltip: boolean;
60
60
  position: "left" | "top" | "bottom" | "right";
61
61
  disabled: boolean;
62
- highlightEffect: "none" | "glow" | "scale" | "border";
62
+ highlightEffect: "none" | "border" | "glow" | "scale";
63
63
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
64
64
  export default _default;
65
65
  //# sourceMappingURL=SkMouseTrapToolTip.vue.d.ts.map
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.34",
6
+ "version": "0.2.35",
7
7
  "sideEffects": false,
8
8
  "main": "./dist/common-ui.umd.js",
9
9
  "module": "./dist/common-ui.es.js",
@@ -47,8 +47,9 @@
47
47
  "@highlightjs/vue-plugin": "^2.1.2",
48
48
  "@mdi/font": "^7.3.67",
49
49
  "@vojtechlanka/vue-tags-input": "^3",
50
- "@vue-skuilder/common": "0.2.34",
51
- "@vue-skuilder/db": "0.2.34",
50
+ "@vue-skuilder/common": "0.2.35",
51
+ "@vue-skuilder/db": "0.2.35",
52
+ "echarts": "6.1.0",
52
53
  "highlight.js": "^11.0.1",
53
54
  "marked": "^15.0.6",
54
55
  "moment": "^2.29.4",
@@ -84,5 +85,5 @@
84
85
  "vite-plugin-dts": "^4.5.3",
85
86
  "vitest": "^4.1.0"
86
87
  },
87
- "stableVersion": "0.2.34"
88
+ "stableVersion": "0.2.35"
88
89
  }
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <div ref="el" :style="{ height: `${height}px`, width: '100%' }" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
7
+ import { init, use, type ECElementEvent, type EChartsCoreOption, type EChartsType } from 'echarts/core';
8
+ import { LineChart, ScatterChart } from 'echarts/charts';
9
+ import {
10
+ DataZoomComponent,
11
+ GridComponent,
12
+ LegendComponent,
13
+ MarkLineComponent,
14
+ TooltipComponent,
15
+ } from 'echarts/components';
16
+ import { CanvasRenderer } from 'echarts/renderers';
17
+
18
+ /**
19
+ * An ECharts canvas for the admin views. Registers only what they draw, so
20
+ * the admin bundle carries a fraction of ECharts. Options are replaced
21
+ * whole on change (`notMerge`): callers compute the full option.
22
+ */
23
+ use([
24
+ LineChart,
25
+ ScatterChart,
26
+ DataZoomComponent,
27
+ GridComponent,
28
+ LegendComponent,
29
+ MarkLineComponent,
30
+ TooltipComponent,
31
+ CanvasRenderer,
32
+ ]);
33
+
34
+ const props = defineProps<{ option: EChartsCoreOption; height: number }>();
35
+ const emit = defineEmits<{ click: [event: ECElementEvent] }>();
36
+
37
+ const el = ref<HTMLElement | null>(null);
38
+ const chart = shallowRef<EChartsType | null>(null);
39
+ let resize: ResizeObserver | null = null;
40
+
41
+ onMounted(() => {
42
+ if (!el.value) return;
43
+ chart.value = init(el.value);
44
+ chart.value.setOption(props.option, { notMerge: true });
45
+ chart.value.on('click', (e) => emit('click', e as ECElementEvent));
46
+ resize = new ResizeObserver(() => chart.value?.resize());
47
+ resize.observe(el.value);
48
+ });
49
+
50
+ watch(
51
+ () => props.option,
52
+ (option) => chart.value?.setOption(option, { notMerge: true })
53
+ );
54
+
55
+ onBeforeUnmount(() => {
56
+ resize?.disconnect();
57
+ chart.value?.dispose();
58
+ });
59
+ </script>
@@ -4,6 +4,7 @@
4
4
  <v-tab value="sessions">Sessions ({{ dataset.sessions.length }})</v-tab>
5
5
  <v-tab value="cards">Cards ({{ dataset.cardHistories.length }})</v-tab>
6
6
  <v-tab v-if="dataset.strategies" value="pipeline">Pipeline</v-tab>
7
+ <v-tab value="elo">ELO</v-tab>
7
8
  </v-tabs>
8
9
 
9
10
  <template v-if="tab === 'sessions'">
@@ -40,6 +41,8 @@
40
41
  :stats="pipelineStats"
41
42
  :stats-label="dataset.username"
42
43
  />
44
+
45
+ <learner-tag-elo v-else-if="tab === 'elo'" :dataset="dataset" :interpreters="interpreters" />
43
46
  </div>
44
47
  </template>
45
48
 
@@ -49,20 +52,21 @@ import { pipelineRunStats, type DiagnosticsInterpreters, type LearnerDataset } f
49
52
  import LearnerCardHistory from './LearnerCardHistory.vue';
50
53
  import LearnerSessionDetail from './LearnerSessionDetail.vue';
51
54
  import LearnerSessionList from './LearnerSessionList.vue';
55
+ import LearnerTagElo from './LearnerTagElo.vue';
52
56
  import PipelineOverview from './PipelineOverview.vue';
53
57
 
54
58
  /**
55
- * One learner: sessions (list, then a session's detail), card history, and,
59
+ * One learner: sessions (list, then a session's detail), card history,
56
60
  * when the dataset carries the course's strategy docs, the pipeline with this
57
- * learner's run stats. Session timelines link into card history. Navigation is internal;
58
- * hosts that want URLs can compose the three views themselves.
61
+ * learner's run stats, and per-tag ELO. Session timelines link into card history. Navigation is internal;
62
+ * hosts that want URLs can compose the views themselves.
59
63
  */
60
64
  const props = defineProps<{
61
65
  dataset: LearnerDataset;
62
66
  interpreters?: DiagnosticsInterpreters;
63
67
  }>();
64
68
 
65
- const tab = ref<'sessions' | 'cards' | 'pipeline'>('sessions');
69
+ const tab = ref<'sessions' | 'cards' | 'pipeline' | 'elo'>('sessions');
66
70
  const sessionId = ref<string | null>(null);
67
71
  const focusCard = ref<string | undefined>(undefined);
68
72
  const pipelineStats = computed(() => pipelineRunStats(props.dataset));