@state-of-geneva/rapports-bdd 1.2.0 → 2.0.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@state-of-geneva/rapports-bdd",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "rapports-bdd": "bin/rapports-bdd.js"
@@ -35,16 +35,12 @@
35
35
  "prepublishOnly": "npm run build"
36
36
  },
37
37
  "dependencies": {
38
- "@cucumber/cucumber-json-converter": "^0.1.0",
39
38
  "@cucumber/gherkin": "^28.0.0",
40
- "@primevue/themes": "^4.5.1",
41
39
  "@vitejs/plugin-vue": "^5.0.5",
42
- "primeicons": "^7.0.0",
43
- "primevue": "^4.5.1",
44
- "quill": "^2.0.3",
45
40
  "vite": "^5.3.1",
46
41
  "vue": "^3.4.21",
47
- "vue-router": "^4.3.0"
42
+ "vue-router": "^4.3.0",
43
+ "vuetify": "^3.13.7"
48
44
  },
49
45
  "devDependencies": {
50
46
  "@rushstack/eslint-patch": "^1.8.0",
package/src/App.vue CHANGED
@@ -1,38 +1,122 @@
1
1
  <script setup lang="ts">
2
- import { RouterView } from 'vue-router'
2
+ import { computed, ref } from 'vue'
3
+ import { RouterView, useRoute } from 'vue-router'
4
+
5
+ const route = useRoute()
6
+ const drawer = ref(false)
7
+ const isHome = computed(() => route.name === 'home')
8
+ const isEditor = computed(() => route.name === 'editor')
3
9
  </script>
4
10
 
5
11
  <template>
6
- <div id="app-container">
7
- <header>
8
- <h1>Rapports BDD</h1>
9
- </header>
10
- <main>
12
+ <v-app>
13
+ <v-app-bar class="app-bar" flat height="76">
14
+ <v-container class="app-bar__content d-flex align-center px-5 px-md-8">
15
+ <v-btn
16
+ class="brand-button px-0"
17
+ variant="text"
18
+ :to="{ name: 'home' }"
19
+ aria-label="Retour à l’accueil Rapports BDD"
20
+ >
21
+ <span class="brand-mark">BDD</span>
22
+ <span class="brand-copy">
23
+ <strong>Rapports BDD</strong>
24
+ <small>Observatoire des tests métier</small>
25
+ </span>
26
+ </v-btn>
27
+
28
+ <v-spacer />
29
+
30
+ <v-btn
31
+ class="desktop-home-button d-none d-sm-flex"
32
+ variant="text"
33
+ :to="{ name: 'home' }"
34
+ :active="isHome"
35
+ >
36
+ Catalogue
37
+ </v-btn>
38
+ <v-chip v-if="!isEditor" class="status-chip d-none d-md-flex ml-3" size="small" variant="tonal">
39
+ <span class="status-dot" /> Rapports à jour
40
+ </v-chip>
41
+ <v-app-bar-nav-icon class="d-flex d-sm-none ml-2" aria-label="Ouvrir le menu" @click="drawer = !drawer" />
42
+ </v-container>
43
+ </v-app-bar>
44
+
45
+ <v-navigation-drawer v-model="drawer" location="right" temporary width="280">
46
+ <v-list nav>
47
+ <v-list-item :to="{ name: 'home' }" title="Catalogue" />
48
+ </v-list>
49
+ </v-navigation-drawer>
50
+
51
+ <v-main class="app-main">
11
52
  <RouterView />
12
- </main>
13
- </div>
53
+ </v-main>
54
+ </v-app>
14
55
  </template>
15
56
 
16
57
  <style scoped>
17
- #app-container {
58
+ .app-bar {
59
+ border-bottom: 1px solid #e6ebe9;
60
+ background: rgba(255, 255, 255, 0.96);
61
+ }
62
+
63
+ .app-bar__content {
64
+ max-width: 1440px;
65
+ height: 100%;
66
+ }
67
+
68
+ .brand-button {
69
+ min-height: 54px;
70
+ text-align: left;
71
+ }
72
+
73
+ .brand-mark {
18
74
  display: grid;
19
- grid-auto-rows: auto 1fr;
20
- grid-template-areas:
21
- 'header'
22
- 'main';
23
- min-height: 100vh;
75
+ width: 42px;
76
+ height: 42px;
77
+ margin-right: 12px;
78
+ place-items: center;
79
+ border-radius: 13px;
80
+ background: #125b50;
81
+ color: white;
82
+ font-size: 12px;
83
+ font-weight: 700;
84
+ letter-spacing: 0.04em;
85
+ }
86
+
87
+ .brand-copy {
88
+ display: flex;
89
+ flex-direction: column;
90
+ gap: 2px;
91
+ color: #172b27;
92
+ line-height: 1.2;
93
+ }
94
+
95
+ .brand-copy strong {
96
+ font-size: 15px;
97
+ font-weight: 700;
98
+ }
99
+
100
+ .brand-copy small {
101
+ color: #73817d;
102
+ font-size: 11px;
103
+ font-weight: 500;
104
+ }
105
+
106
+ .status-chip {
107
+ color: #176b48;
108
+ font-weight: 600;
24
109
  }
25
110
 
26
- header {
27
- grid-area: header;
28
- color: var(--primary);
29
- background-color: var(--accent);
30
- text-align: center;
111
+ .status-dot {
112
+ width: 7px;
113
+ height: 7px;
114
+ margin-right: 7px;
115
+ border-radius: 50%;
116
+ background: #25a56a;
31
117
  }
32
118
 
33
- main {
34
- grid-area: main;
35
- color: var(--secondary);
36
- background-color: var(--primary);
119
+ .app-main {
120
+ min-height: calc(100vh - 76px);
37
121
  }
38
122
  </style>
@@ -1,18 +1,70 @@
1
1
  :root {
2
- --primary: #eff0f0;
3
- --secondary: #173647;
4
- --accent: #1dbb68;
2
+ font-family: 'DM Sans', 'Segoe UI', sans-serif;
3
+ color: #172b27;
4
+ background: #f4f6f8;
5
+ font-synthesis: none;
6
+ text-rendering: optimizeLegibility;
7
+ -webkit-font-smoothing: antialiased;
8
+ -moz-osx-font-smoothing: grayscale;
9
+ font-optical-sizing: auto;
5
10
  }
6
11
 
7
- #app,
12
+ html,
8
13
  body,
9
- html {
10
- min-height: 100vh;
14
+ #app {
15
+ min-width: 320px;
16
+ min-height: 100%;
11
17
  margin: 0;
12
- padding: 0;
13
- font-family: Arial, sans-serif;
14
18
  }
15
19
 
16
- .p-tree-node-toggle-button {
17
- align-self: start;
20
+ body {
21
+ min-height: 100vh;
22
+ }
23
+
24
+ button,
25
+ a,
26
+ input {
27
+ font: inherit;
28
+ }
29
+
30
+ button:focus-visible,
31
+ a:focus-visible,
32
+ [role='button']:focus-visible {
33
+ outline: 3px solid rgba(18, 91, 80, 0.35);
34
+ outline-offset: 2px;
35
+ }
36
+
37
+ .text-icon {
38
+ display: inline-flex;
39
+ min-width: 1em;
40
+ align-items: center;
41
+ justify-content: center;
42
+ font-family: 'DM Sans', sans-serif;
43
+ font-size: 1.1em;
44
+ font-weight: 600;
45
+ line-height: 1;
46
+ }
47
+
48
+ .v-application {
49
+ background: #f4f6f8 !important;
50
+ font-family: 'DM Sans', 'Segoe UI', sans-serif;
51
+ }
52
+
53
+ .v-btn {
54
+ font-weight: 600;
55
+ }
56
+
57
+ .v-field--variant-outlined .v-field__outline {
58
+ --v-field-border-opacity: 0.13;
59
+ }
60
+
61
+ @media (prefers-reduced-motion: reduce) {
62
+ *,
63
+ *::before,
64
+ *::after {
65
+ scroll-behavior: auto !important;
66
+ animation-duration: 0.01ms !important;
67
+ animation-iteration-count: 1 !important;
68
+ transition-duration: 0.01ms !important;
69
+ }
18
70
  }
@@ -1,70 +1,39 @@
1
- <template>
2
- <div class="example" v-for="example in examples" :key="example.id">
3
-
4
- <div class="title">
5
- <b>{{ example.keyword }}: </b> {{ example.name }}
6
- </div>
7
- <table>
8
- <thead v-if="example.tableHeader">
9
- <tr>
10
- <th v-for="cell in example.tableHeader.cells" :key="cell.value">
11
- {{cell.value}}
12
- </th>
13
- </tr>
14
- </thead>
15
- <tbody>
16
- <tr v-for="row in example.tableBody" :key="row.id">
17
- <td v-for="cell in row.cells" :key="cell.value">
18
- {{cell.value}}
19
- </td>
20
- </tr>
21
- </tbody>
22
- </table>
23
- </div>
24
- </template>
25
1
  <script setup lang="ts">
26
2
  import type { PropType } from 'vue'
27
- import * as Messages from '@cucumber/messages'
3
+ import type * as Messages from '@cucumber/messages'
4
+
28
5
  defineProps({
29
6
  examples: {
30
- type: Object as PropType<Array<Messages.Examples>>,
31
- required: true,
32
- },
33
- });
7
+ type: Array as PropType<readonly Messages.Examples[]>,
8
+ required: true
9
+ }
10
+ })
34
11
  </script>
35
- <style scoped>
36
- .title{
37
- padding-bottom: 5px;
38
- }
39
- .example{
40
- padding-top: 10px;
41
- }
42
- table {
43
- display: table;
44
- border-collapse: separate;
45
- box-sizing: border-box;
46
- text-indent: initial;
47
- unicode-bidi: isolate;
48
- border-spacing: 2px;
49
- border-color: gray;
50
- }
51
12
 
52
- tr {
53
- display: table-row;
54
- vertical-align: inherit;
55
- unicode-bidi: isolate;
56
- border-color: inherit;
57
- }
58
-
59
- td, th {
60
- padding: .4em .6em;
61
- border-width: 0 2px 0 0;
62
- border-style: solid;
63
- border-color: #000080;
64
- color: #297bde;
65
- }
13
+ <template>
14
+ <section v-for="example in examples" :key="example.id" class="example">
15
+ <h4><strong>{{ example.keyword }} :</strong> {{ example.name }}</h4>
16
+ <div class="table-scroll">
17
+ <table class="examples-table">
18
+ <thead v-if="example.tableHeader"><tr>
19
+ <th v-for="(cell, index) in example.tableHeader.cells" :key="`${index}-${cell.value}`">{{ cell.value }}</th>
20
+ </tr></thead>
21
+ <tbody><tr v-for="row in example.tableBody" :key="row.id">
22
+ <td v-for="(cell, index) in row.cells" :key="`${row.id}-${index}`">{{ cell.value }}</td>
23
+ </tr></tbody>
24
+ </table>
25
+ </div>
26
+ </section>
27
+ </template>
66
28
 
67
- td:first-child, th:first-child {
68
- border-width: 0 2px;
69
- }
29
+ <style scoped>
30
+ .example { margin-top: 13px; }
31
+ .example h4 { margin: 0 0 8px; color: #566862; font-size: 11px; font-weight: 500; }
32
+ .example h4 strong { color: #176b58; font-weight: 700; }
33
+ .table-scroll { max-width: 100%; overflow-x: auto; }
34
+ .examples-table { width: max-content; min-width: 45%; border-collapse: separate; border-spacing: 0; border: 1px solid #dfe9e5; border-radius: 8px; color: #4c6059; font-size: 11px; overflow: hidden; }
35
+ .examples-table th, .examples-table td { padding: 7px 11px; border-right: 1px solid #e3ebe7; border-bottom: 1px solid #e3ebe7; text-align: left; white-space: nowrap; }
36
+ .examples-table th { background: #f2f7f4; color: #285d4f; font-weight: 600; }
37
+ .examples-table tr:last-child td { border-bottom: 0; }
38
+ .examples-table th:last-child, .examples-table td:last-child { border-right: 0; }
70
39
  </style>
@@ -1,65 +1,39 @@
1
- <template>
2
- <div class="step" v-for="step in steps" :key="step.id">
3
-
4
- <div class="title">
5
- <b>{{ step.keyword }}</b> {{ step.text }}
6
- </div>
7
- <pre v-if="step?.docString?.content">{{step?.docString?.content}}</pre>
8
- <table v-if="step.dataTable">
9
- <tbody>
10
-
11
- <tr v-for="(row, rowIndex) in step.dataTable.rows" :key="row.id ?? rowIndex">
12
- <td v-for="(cell, cellIndex) in row.cells" :key="cell.value ?? cellIndex">
13
- {{cell.value}}
14
- </td>
15
- </tr>
16
- </tbody>
17
- </table>
18
- </div>
19
- </template>
20
-
21
1
  <script setup lang="ts">
22
2
  import type { PropType } from 'vue'
23
- import * as Messages from '@cucumber/messages'
3
+ import type * as Messages from '@cucumber/messages'
4
+
24
5
  defineProps({
25
6
  steps: {
26
- type: Object as PropType<Array<Messages.Step>>,
27
- required: true,
28
- },
29
- });
7
+ type: Array as PropType<readonly Messages.Step[]>,
8
+ required: true
9
+ }
10
+ })
30
11
  </script>
31
- <style scoped>
32
12
 
33
- .step {
34
- padding-left: 20px;
35
- }
36
-
37
- table {
38
- display: table;
39
- border-collapse: separate;
40
- box-sizing: border-box;
41
- text-indent: initial;
42
- unicode-bidi: isolate;
43
- border-spacing: 2px;
44
- border-color: gray;
45
- }
46
-
47
- tr {
48
- display: table-row;
49
- vertical-align: inherit;
50
- unicode-bidi: isolate;
51
- border-color: inherit;
52
- }
53
-
54
- td, th {
55
- padding: .4em .6em;
56
- border-width: 0 2px 0 0;
57
- border-style: solid;
58
- border-color: #000080;
59
- color: #297bde;
60
- }
13
+ <template>
14
+ <div class="steps">
15
+ <div v-for="step in steps" :key="step.id" class="step">
16
+ <div class="step__title"><strong>{{ step.keyword.trim() }}</strong><span>{{ step.text }}</span></div>
17
+ <pre v-if="step.docString?.content" class="doc-string">{{ step.docString.content }}</pre>
18
+ <div v-if="step.dataTable" class="table-scroll">
19
+ <table class="data-table"><tbody>
20
+ <tr v-for="(row, rowIndex) in step.dataTable.rows" :key="row.id || rowIndex">
21
+ <td v-for="(cell, cellIndex) in row.cells" :key="`${rowIndex}-${cellIndex}`">{{ cell.value }}</td>
22
+ </tr>
23
+ </tbody></table>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
61
28
 
62
- td:first-child, th:first-child {
63
- border-width: 0 2px;
64
- }
29
+ <style scoped>
30
+ .steps { display: grid; gap: 7px; margin-top: 10px; }
31
+ .step { position: relative; padding-left: 14px; border-left: 2px solid #e5efeb; }
32
+ .step__title { display: flex; flex-wrap: wrap; gap: 5px; color: #53645f; font-size: 12px; line-height: 1.6; }
33
+ .step__title strong { color: #176b58; font-weight: 600; }
34
+ .doc-string { overflow-x: auto; margin: 7px 0 5px; padding: 10px 12px; border: 1px solid #e9eeec; border-radius: 8px; background: #f7f9f8; color: #435751; font-family: 'Consolas', 'Courier New', monospace; font-size: 11px; line-height: 1.6; }
35
+ .table-scroll { max-width: 100%; overflow-x: auto; margin-top: 7px; }
36
+ .data-table { border-collapse: collapse; color: #4c6059; font-size: 11px; }
37
+ .data-table td { padding: 6px 10px; border: 1px solid #dfe9e5; white-space: nowrap; }
38
+ .data-table tr:first-child td { background: #f4f8f6; color: #285d4f; font-weight: 600; }
65
39
  </style>
@@ -1,48 +1,24 @@
1
- <template>
2
- <div class="tags" v-if="tags?.length > 0">
3
- <Tag severity="info" :value="tag.name" rounded v-for="tag in tags" :key="tag.name"></Tag>
4
- <br />
5
- </div>
6
- </template>
7
-
8
1
  <script setup lang="ts">
9
2
  import type { PropType } from 'vue'
10
- import * as Messages from '@cucumber/messages'
3
+ import type * as Messages from '@cucumber/messages'
4
+
11
5
  defineProps({
12
6
  tags: {
13
- type: Object as PropType<Array<Messages.Tag>>,
14
- required: true,
15
- },
16
- });
7
+ type: Array as PropType<readonly Messages.Tag[]>,
8
+ required: true
9
+ }
10
+ })
17
11
  </script>
18
- <style scoped>
19
12
 
20
- .tags {
21
- --p-tag-font-size: 12px;
22
- }
23
-
24
- table {
25
- display: table;
26
- border-collapse: separate;
27
- box-sizing: border-box;
28
- text-indent: initial;
29
- unicode-bidi: isolate;
30
- border-spacing: 2px;
31
- border-color: gray;
32
- }
33
-
34
- tr {
35
- display: table-row;
36
- vertical-align: inherit;
37
- unicode-bidi: isolate;
38
- border-color: inherit;
39
- }
13
+ <template>
14
+ <div v-if="tags.length" class="tags" aria-label="Étiquettes Gherkin">
15
+ <v-chip v-for="tag in tags" :key="tag.id" size="x-small" variant="tonal" color="primary" class="tag-chip">
16
+ {{ tag.name }}
17
+ </v-chip>
18
+ </div>
19
+ </template>
40
20
 
41
- td, th {
42
- padding: .4em .6em;
43
- border-width: 0 2px;
44
- border-style: solid;
45
- border-color: #000080;
46
- color: #297bde;
47
- }
21
+ <style scoped>
22
+ .tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
23
+ .tag-chip { height: 22px; font-family: 'Consolas', 'Courier New', monospace; font-size: 10px; font-weight: 500; }
48
24
  </style>
@@ -0,0 +1,51 @@
1
+ <script setup lang="ts">
2
+ import type { MenuEntry } from '@/models/menu-categorie'
3
+
4
+ defineProps<{ item: MenuEntry }>()
5
+ </script>
6
+
7
+ <template>
8
+ <v-list-group v-if="item.items?.length" :value="item.label" class="project-menu-group">
9
+ <template #activator="{ props }">
10
+ <v-list-item v-bind="props" :title="item.label" />
11
+ </template>
12
+ <v-list class="nested-project-list" density="comfortable" nav>
13
+ <ProjectMenuItem v-for="child in item.items" :key="child.label" :item="child" />
14
+ </v-list>
15
+ </v-list-group>
16
+ <v-list-item
17
+ v-else
18
+ :to="item.url"
19
+ :title="item.label"
20
+ rounded="lg"
21
+ class="project-link"
22
+ >
23
+ <template #append><span class="list-arrow">→</span></template>
24
+ </v-list-item>
25
+ </template>
26
+
27
+ <style scoped>
28
+ .project-link {
29
+ min-height: 43px;
30
+ color: #3984c6;
31
+ font-size: 13px;
32
+ }
33
+
34
+ .project-link :deep(.v-list-item-title) {
35
+ color: inherit;
36
+ }
37
+
38
+ .list-arrow {
39
+ color: #93a39e;
40
+ font-size: 15px;
41
+ transition: transform 0.18s ease;
42
+ }
43
+
44
+ .project-link:hover .list-arrow {
45
+ transform: translateX(3px);
46
+ }
47
+
48
+ .nested-project-list {
49
+ padding-inline-start: 12px;
50
+ }
51
+ </style>