@quazardous/qdadm 2.32.0 → 2.33.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.
Files changed (36) hide show
  1. package/dist/styles/qdadm.css +1 -1
  2. package/package.json +8 -2
  3. package/src/components/display/EmailPreview.vue +227 -0
  4. package/src/components/display/EntityTimeline.vue +408 -0
  5. package/src/components/display/LogStream.vue +364 -0
  6. package/src/components/display/PayloadDiff.vue +236 -0
  7. package/src/components/display/PayloadViewer.vue +246 -0
  8. package/src/components/index.ts +8 -0
  9. package/src/components/layout/AppLayout.vue +8 -0
  10. package/src/components/tasks/TaskDialog.vue +95 -0
  11. package/src/components/tasks/TaskHost.vue +45 -0
  12. package/src/components/tasks/TaskTray.vue +54 -0
  13. package/src/composables/index.ts +11 -0
  14. package/src/composables/useListPage.filters.ts +26 -1
  15. package/src/composables/useLogStream.ts +264 -0
  16. package/src/email/index.ts +46 -0
  17. package/src/entity/storage/SdkStorage.ts +53 -1
  18. package/src/entity/storage/index.ts +2 -0
  19. package/src/i18n/defaults/core.en.generated.ts +85 -0
  20. package/src/i18n/defaults/core.en.yml +85 -0
  21. package/src/i18n/defaults/core.fr.generated.ts +85 -0
  22. package/src/i18n/defaults/core.fr.yml +85 -0
  23. package/src/index.ts +21 -0
  24. package/src/kernel/Kernel.vue.ts +9 -2
  25. package/src/styles/_email.scss +188 -0
  26. package/src/styles/_log-stream.scss +167 -0
  27. package/src/styles/_payload.scss +312 -0
  28. package/src/styles/_tasks.scss +212 -0
  29. package/src/styles/_timeline.scss +229 -0
  30. package/src/styles/index.scss +5 -0
  31. package/src/tasks/taskStore.ts +460 -0
  32. package/src/tasks/useTaskRunner.ts +52 -0
  33. package/src/utils/ansi.ts +127 -0
  34. package/src/utils/email.ts +270 -0
  35. package/src/utils/index.ts +32 -0
  36. package/src/utils/payload.ts +480 -0
@@ -69,6 +69,91 @@ core:
69
69
  notRegistered: non enregistrée
70
70
  remove: Retirer
71
71
  via: "via {origin}"
72
+ # LogStream (#4110)
73
+ log:
74
+ streaming: En cours
75
+ done: Terminé
76
+ stopped: Arrêté
77
+ failed: "Échec : {error}"
78
+ lines: "{count} lignes"
79
+ search: Chercher dans le log
80
+ previous: Occurrence précédente
81
+ next: Occurrence suivante
82
+ onlyMatches: Seulement les lignes trouvées
83
+ errors: "{count} erreurs"
84
+ firstError: Aller à la ligne d'erreur suivante
85
+ wrap: Couper les lignes longues
86
+ follow: Suivre la fin du log
87
+ download: Télécharger le log
88
+ newLines: "{count} nouvelles lignes, reprendre"
89
+ empty: Rien pour l'instant
90
+ # EntityTimeline (#4111)
91
+ timeline:
92
+ actors: Filtrer par acteur
93
+ loading: Chargement…
94
+ empty: Rien ne s'est encore passé
95
+ newEvents: "{count} nouveaux événements"
96
+ oldestFirst: Plus anciens d'abord
97
+ newestFirst: Plus récents d'abord
98
+ # PayloadViewer / PayloadDiff (#4112)
99
+ payload:
100
+ headers: "En-têtes ({count})"
101
+ headerRow: La première ligne est un en-tête
102
+ copy: Copier
103
+ copied: Copié dans le presse-papiers
104
+ copyFailed: Copie impossible
105
+ download: Télécharger
106
+ showAll: "Afficher les {count} lignes"
107
+ binary: "Contenu binaire, {size}. Premiers octets :"
108
+ malformed: "{format} invalide ({error}), affiché comme texte"
109
+ expected: Attendu
110
+ captured: Capturé
111
+ identical: Identiques
112
+ unchanged: "{count} lignes inchangées"
113
+ showSame: "Afficher les {count} lignes inchangées"
114
+ inline: En ligne
115
+ split: Côte à côte
116
+ # EmailPreview (#4113)
117
+ email:
118
+ from: De
119
+ to: À
120
+ cc: Cc
121
+ replyTo: Répondre à
122
+ date: Date
123
+ noSubject: (sans objet)
124
+ allHeaders: "Tous les en-têtes ({count})"
125
+ noParser: "Un message brut demande un parser : passer parseMime de @quazardous/qdadm/email. La source est affichée."
126
+ tab:
127
+ html: HTML
128
+ text: Texte
129
+ source: Source
130
+ imagesBlocked: "{count} images distantes bloquées"
131
+ loadImages: Charger les images
132
+ blockImages: Bloquer les images
133
+ empty: Ce mail n'a pas de contenu
134
+ unnamed: (sans nom)
135
+ inline: intégrée
136
+ download: Télécharger
137
+ # TaskRunner (#4114)
138
+ task:
139
+ status:
140
+ starting: Démarrage
141
+ queued: En attente
142
+ running: En cours
143
+ succeeded: Terminée
144
+ failed: Échouée
145
+ cancelled: Annulée
146
+ cancel: Annuler la tâche
147
+ close: Fermer
148
+ background: Continuer en arrière-plan
149
+ open: Ouvrir la tâche
150
+ readError: "Lecture de la tâche impossible ({error}), nouvel essai"
151
+ start: Lancer
152
+ dontStart: Ne pas lancer
153
+ typeToConfirm: "Taper {value} pour confirmer"
154
+ tray: "{count} tâches en cours"
155
+ trayDone: Tâches récentes
156
+ clear: Effacer les terminées
72
157
  # The breadcrumb's View↔Edit toggle (useNavContext).
73
158
  breadcrumb:
74
159
  view: Voir
package/src/index.ts CHANGED
@@ -327,6 +327,16 @@ export {
327
327
  type LayoutMeta,
328
328
  } from './composables/useLayoutResolver'
329
329
  export { useSSEBridge, type UseSSEBridgeReturn } from './composables/useSSEBridge'
330
+ export {
331
+ useLogStream,
332
+ type LogSource,
333
+ type LogLine,
334
+ type LogPollResult,
335
+ type LogPushApi,
336
+ type LogStreamStatus,
337
+ type UseLogStreamOptions,
338
+ type UseLogStreamReturn,
339
+ } from './composables/useLogStream'
330
340
 
331
341
  // Route-state persistence (#2146) — where a route remembers what it shows.
332
342
  export {
@@ -396,6 +406,17 @@ export { useSidebarState, SIDEBAR_COLLAPSED_KEY } from './composables/useSidebar
396
406
  // COMPONENTS
397
407
  // ════════════════════════════════════════════════════════════════════════════
398
408
  export * from './components/index'
409
+ export { useTaskRunner, taskAction } from './tasks/useTaskRunner'
410
+ export {
411
+ getTaskStore,
412
+ registerTaskKind,
413
+ type TaskRun,
414
+ type TaskStatus,
415
+ type TaskKind,
416
+ type TaskFollow,
417
+ type TaskConfirm,
418
+ type RunOptions,
419
+ } from './tasks/taskStore'
399
420
 
400
421
  // ════════════════════════════════════════════════════════════════════════════
401
422
  // MODULE SYSTEM (excluding types that conflict)
@@ -3,6 +3,8 @@ import {
3
3
  h,
4
4
  defineComponent,
5
5
  ref,
6
+ shallowRef,
7
+ markRaw,
6
8
  onErrorCaptured,
7
9
  type App,
8
10
  type Component,
@@ -43,7 +45,10 @@ export function getQdadmDebugBarRef(): Ref<Component | null> {
43
45
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
46
  const w = typeof window !== 'undefined' ? (window as any) : null
45
47
  if (w && w[QDADM_DEBUG_BAR_GLOBAL_KEY]) return w[QDADM_DEBUG_BAR_GLOBAL_KEY]
46
- const r = ref<Component | null>(null)
48
+ // Shallow (#4117): a deep ref turns the component into a reactive proxy,
49
+ // and Vue warns "received a Component that was made a reactive object" on
50
+ // every render of the bar.
51
+ const r = shallowRef<Component | null>(null)
47
52
  if (w) w[QDADM_DEBUG_BAR_GLOBAL_KEY] = r
48
53
  return r
49
54
  }
@@ -56,7 +61,9 @@ export const qdadmDebugBarRef: Ref<Component | null> = getQdadmDebugBarRef()
56
61
  * constructor). Equivalent to `getQdadmDebugBarRef().value = component`.
57
62
  */
58
63
  export function setQdadmDebugBar(component: Component | null): void {
59
- getQdadmDebugBarRef().value = component
64
+ // markRaw as well: the ref on window may be a deep one left by an older
65
+ // copy of this module (HMR keeps it across versions).
66
+ getQdadmDebugBarRef().value = component ? markRaw(component) : null
60
67
  }
61
68
 
62
69
  /**
@@ -0,0 +1,188 @@
1
+ /**
2
+ * EmailPreview (#4113)
3
+ */
4
+
5
+ @use 'variables' as *;
6
+
7
+ .qd-email {
8
+ border: 1px solid var(--p-surface-200);
9
+ border-radius: $radius-sm;
10
+ overflow: hidden;
11
+ min-width: 0;
12
+ background: var(--p-surface-0);
13
+ }
14
+
15
+ .qd-email-head {
16
+ padding: 0.75rem 1rem 0.5rem;
17
+ border-bottom: 1px solid var(--p-surface-200);
18
+ }
19
+
20
+ .qd-email-subject {
21
+ margin: 0 0 0.5rem;
22
+ font-size: 1.0625rem;
23
+ font-weight: 600;
24
+ overflow-wrap: anywhere;
25
+ }
26
+
27
+ .qd-email-main {
28
+ display: grid;
29
+ grid-template-columns: max-content minmax(0, 1fr);
30
+ gap: 0.125rem 0.75rem;
31
+ margin: 0;
32
+ font-size: $font-size-sm;
33
+
34
+ dt {
35
+ color: var(--p-text-muted-color);
36
+ }
37
+
38
+ dd {
39
+ margin: 0;
40
+ overflow-wrap: anywhere;
41
+ }
42
+ }
43
+
44
+ .qd-email-headers {
45
+ margin-top: 0.5rem;
46
+ font-size: $font-size-xs;
47
+
48
+ summary {
49
+ cursor: pointer;
50
+ color: var(--p-text-muted-color);
51
+ }
52
+
53
+ table {
54
+ margin-top: 0.25rem;
55
+ border-collapse: collapse;
56
+ font-family: $font-family-mono;
57
+ }
58
+
59
+ th {
60
+ padding: 0.0625rem 1rem 0.0625rem 0;
61
+ text-align: left;
62
+ font-weight: 600;
63
+ white-space: nowrap;
64
+ vertical-align: top;
65
+ }
66
+
67
+ td {
68
+ overflow-wrap: anywhere;
69
+ }
70
+ }
71
+
72
+ .qd-email-warning {
73
+ padding: 0.375rem 1rem;
74
+ background: var(--p-orange-50);
75
+ color: var(--p-orange-800);
76
+ font-size: $font-size-sm;
77
+ }
78
+
79
+ .qd-email-tabs {
80
+ display: flex;
81
+ flex-wrap: wrap;
82
+ align-items: center;
83
+ gap: 0.25rem;
84
+ padding: 0 0.5rem;
85
+ border-bottom: 1px solid var(--p-surface-200);
86
+ font-size: $font-size-sm;
87
+ }
88
+
89
+ .qd-email-tab {
90
+ padding: 0.5rem 0.75rem;
91
+ border: none;
92
+ border-bottom: 2px solid transparent;
93
+ background: transparent;
94
+ color: var(--p-text-muted-color);
95
+ font: inherit;
96
+ cursor: pointer;
97
+
98
+ &--active {
99
+ border-bottom-color: var(--p-primary-color);
100
+ color: var(--p-text-color);
101
+ font-weight: 600;
102
+ }
103
+ }
104
+
105
+ .qd-email-spacer {
106
+ flex: 1;
107
+ }
108
+
109
+ .qd-email-blocked {
110
+ color: var(--p-text-muted-color);
111
+ font-size: $font-size-xs;
112
+ }
113
+
114
+ .qd-email-frame-wrap {
115
+ resize: vertical;
116
+ overflow: hidden;
117
+ min-height: 8rem;
118
+ background: #fff;
119
+ }
120
+
121
+ .qd-email-frame {
122
+ display: block;
123
+ width: 100%;
124
+ height: 100%;
125
+ border: 0;
126
+ }
127
+
128
+ .qd-email-text {
129
+ margin: 0;
130
+ padding: 0.75rem 1rem;
131
+ max-height: 32rem;
132
+ overflow: auto;
133
+ white-space: pre-wrap;
134
+ overflow-wrap: anywhere;
135
+ font-family: $font-family-mono;
136
+ font-size: 0.8125rem;
137
+ }
138
+
139
+ .qd-email-source {
140
+ white-space: pre;
141
+ }
142
+
143
+ .qd-email-empty {
144
+ padding: 0.75rem 1rem;
145
+ color: var(--p-text-muted-color);
146
+ font-style: italic;
147
+ }
148
+
149
+ .qd-email-attachments {
150
+ list-style: none;
151
+ margin: 0;
152
+ padding: 0.25rem 0.5rem;
153
+ border-top: 1px solid var(--p-surface-200);
154
+ }
155
+
156
+ .qd-email-attachment {
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 0.5rem;
160
+ padding: 0.25rem;
161
+ font-size: $font-size-sm;
162
+ min-width: 0;
163
+ }
164
+
165
+ .qd-email-thumb {
166
+ width: 2.5rem;
167
+ height: 2.5rem;
168
+ object-fit: cover;
169
+ border-radius: $radius-sm;
170
+ border: 1px solid var(--p-surface-200);
171
+ }
172
+
173
+ .qd-email-clip {
174
+ width: 2.5rem;
175
+ text-align: center;
176
+ color: var(--p-text-muted-color);
177
+ }
178
+
179
+ .qd-email-att-name {
180
+ font-weight: 500;
181
+ overflow-wrap: anywhere;
182
+ }
183
+
184
+ .qd-email-att-meta {
185
+ flex: 1;
186
+ color: var(--p-text-muted-color);
187
+ font-size: $font-size-xs;
188
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * LogStream (#4110)
3
+ * A terminal-like panel: dark in both themes, as logs are read.
4
+ */
5
+
6
+ @use 'variables' as *;
7
+
8
+ .qd-log-stream {
9
+ --qd-log-bg: #1e1e1e;
10
+ --qd-log-fg: #d4d4d4;
11
+ --qd-log-muted: #858585;
12
+ --qd-log-mark: rgba(255, 213, 79, 0.45);
13
+ --qd-log-error-bg: rgba(241, 76, 76, 0.14);
14
+ --qd-log-current: rgba(59, 142, 234, 0.3);
15
+
16
+ position: relative;
17
+ display: flex;
18
+ flex-direction: column;
19
+ border: 1px solid var(--p-surface-300);
20
+ border-radius: $radius-sm;
21
+ overflow: hidden;
22
+ min-width: 0;
23
+ }
24
+
25
+ .qd-log-toolbar {
26
+ display: flex;
27
+ flex-wrap: wrap;
28
+ align-items: center;
29
+ gap: 0.25rem 0.5rem;
30
+ padding: 0.25rem 0.5rem;
31
+ background: var(--p-surface-50);
32
+ border-bottom: 1px solid var(--p-surface-200);
33
+ font-size: $font-size-sm;
34
+ }
35
+
36
+ .qd-log-spacer-x {
37
+ flex: 1;
38
+ }
39
+
40
+ .qd-log-status {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ gap: 0.375rem;
44
+ font-weight: 500;
45
+ }
46
+
47
+ .qd-log-status-dot {
48
+ width: 0.5rem;
49
+ height: 0.5rem;
50
+ border-radius: 50%;
51
+ background: var(--p-surface-400);
52
+
53
+ .qd-log-status--streaming & {
54
+ background: var(--p-green-500);
55
+ animation: qd-log-pulse 1.2s ease-in-out infinite;
56
+ }
57
+ .qd-log-status--done & {
58
+ background: var(--p-blue-500);
59
+ }
60
+ .qd-log-status--error & {
61
+ background: var(--p-red-500);
62
+ }
63
+ }
64
+
65
+ @keyframes qd-log-pulse {
66
+ 50% {
67
+ opacity: 0.3;
68
+ }
69
+ }
70
+
71
+ .qd-log-count,
72
+ .qd-log-search-count {
73
+ color: var(--p-text-muted-color);
74
+ font-size: $font-size-xs;
75
+ font-variant-numeric: tabular-nums;
76
+ }
77
+
78
+ .qd-log-search {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ gap: 0.125rem;
82
+
83
+ .p-inputtext {
84
+ width: 12rem;
85
+ max-width: 40vw;
86
+ }
87
+ }
88
+
89
+ .qd-log-viewport {
90
+ overflow: auto;
91
+ background: var(--qd-log-bg);
92
+ color: var(--qd-log-fg);
93
+ font-family: $font-family-mono;
94
+ font-size: 0.8125rem;
95
+ line-height: var(--qd-log-line-height, 20px);
96
+ outline: none;
97
+ }
98
+
99
+ .qd-log-empty {
100
+ padding: 0.75rem 1rem;
101
+ color: var(--qd-log-muted);
102
+ font-style: italic;
103
+ }
104
+
105
+ .qd-log-line {
106
+ display: flex;
107
+ height: var(--qd-log-line-height, 20px);
108
+ white-space: pre;
109
+ padding-right: 0.75rem;
110
+
111
+ &--error {
112
+ background: var(--qd-log-error-bg);
113
+ }
114
+ &--current {
115
+ background: var(--qd-log-current);
116
+ }
117
+
118
+ .qd-log-stream--wrap & {
119
+ height: auto;
120
+ min-height: var(--qd-log-line-height, 20px);
121
+ white-space: pre-wrap;
122
+ word-break: break-word;
123
+ content-visibility: auto;
124
+ contain-intrinsic-size: auto var(--qd-log-line-height, 20px);
125
+ }
126
+ }
127
+
128
+ .qd-log-n {
129
+ flex: none;
130
+ min-width: 3.5rem;
131
+ padding: 0 0.75rem 0 0.5rem;
132
+ text-align: right;
133
+ color: var(--qd-log-muted);
134
+ user-select: none;
135
+ }
136
+
137
+ .qd-log-text {
138
+ flex: 1;
139
+ min-width: 0;
140
+ }
141
+
142
+ .qd-log-ts {
143
+ color: var(--qd-log-muted);
144
+ }
145
+
146
+ .qd-log-mark {
147
+ background: var(--qd-log-mark);
148
+ border-radius: 2px;
149
+ }
150
+
151
+ .qd-log-resume {
152
+ position: absolute;
153
+ bottom: 0.75rem;
154
+ left: 50%;
155
+ transform: translateX(-50%);
156
+ display: inline-flex;
157
+ align-items: center;
158
+ gap: 0.375rem;
159
+ padding: 0.25rem 0.75rem;
160
+ border: none;
161
+ border-radius: 999px;
162
+ background: var(--p-primary-color);
163
+ color: var(--p-primary-contrast-color);
164
+ font-size: $font-size-xs;
165
+ cursor: pointer;
166
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
167
+ }