@tekkare/romulus 0.1.226 → 0.1.228
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/dist/module.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bouton qui disparait n'apprend pas pourquoi.
|
|
14
14
|
-->
|
|
15
15
|
<script setup lang="ts">
|
|
16
|
-
import { computed } from 'vue'
|
|
16
|
+
import { computed, reactive } from 'vue'
|
|
17
17
|
import type { RmAlert, RmAlertEvent, RmAlertMenuItem } from '../utils/alerts'
|
|
18
18
|
|
|
19
19
|
const props = withDefaults(
|
|
@@ -36,6 +36,12 @@ const props = withDefaults(
|
|
|
36
36
|
expandedEvents?: RmAlertEvent[]
|
|
37
37
|
expandedLoading?: boolean
|
|
38
38
|
lang?: 'fr' | 'en'
|
|
39
|
+
/**
|
|
40
|
+
* Sections rendues repliees, par leur libelle (`group`). Pour ce qui se
|
|
41
|
+
* consulte rarement, comme les alertes posees depuis une autre app : la
|
|
42
|
+
* liste reste complete sans que ces cartes passent devant.
|
|
43
|
+
*/
|
|
44
|
+
collapsedGroups?: string[]
|
|
39
45
|
}>(),
|
|
40
46
|
{
|
|
41
47
|
events: () => [],
|
|
@@ -49,6 +55,7 @@ const props = withDefaults(
|
|
|
49
55
|
expandedEvents: () => [],
|
|
50
56
|
expandedLoading: false,
|
|
51
57
|
lang: 'fr',
|
|
58
|
+
collapsedGroups: () => [],
|
|
52
59
|
},
|
|
53
60
|
)
|
|
54
61
|
|
|
@@ -129,6 +136,9 @@ const sections = computed(() => {
|
|
|
129
136
|
return order.map((label) => ({ label, alerts: byLabel.get(label)! }))
|
|
130
137
|
})
|
|
131
138
|
|
|
139
|
+
/** Sections repliables ouvertes a la main. Toutes fermees au depart. */
|
|
140
|
+
const opened = reactive<Record<string, boolean>>({})
|
|
141
|
+
|
|
132
142
|
const unreadTotal = computed(() =>
|
|
133
143
|
props.alerts.reduce((total, alert) => total + (alert.unreadCount ?? 0), 0),
|
|
134
144
|
)
|
|
@@ -200,30 +210,52 @@ function setTab(value: 'active' | 'paused' | 'events') {
|
|
|
200
210
|
|
|
201
211
|
<template v-else>
|
|
202
212
|
<div v-if="sections.length" class="rm-alerts__list">
|
|
203
|
-
<section
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
213
|
+
<template v-for="section in sections" :key="section.label">
|
|
214
|
+
<RmCollapse
|
|
215
|
+
v-if="section.label && collapsedGroups.includes(section.label)"
|
|
216
|
+
:model-value="!!opened[section.label]"
|
|
217
|
+
:title="section.label"
|
|
218
|
+
:count="section.alerts.length"
|
|
219
|
+
@update:model-value="opened[section.label] = $event"
|
|
220
|
+
>
|
|
221
|
+
<div class="rm-alerts__section">
|
|
222
|
+
<RmAlertCard
|
|
223
|
+
v-for="alert in section.alerts"
|
|
224
|
+
:key="alert.id"
|
|
225
|
+
:alert="alert"
|
|
226
|
+
:menu="menu"
|
|
227
|
+
:lang="lang"
|
|
228
|
+
:on-watched-page="onWatchedPage"
|
|
229
|
+
:expanded="expandedId === alert.id"
|
|
230
|
+
:events="expandedId === alert.id ? expandedEvents : []"
|
|
231
|
+
:events-loading="expandedId === alert.id && expandedLoading"
|
|
232
|
+
@open="emit('open', $event)"
|
|
233
|
+
@rearm="emit('rearm', $event)"
|
|
234
|
+
@menu="emit('menu', $event)"
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
</RmCollapse>
|
|
238
|
+
<section v-else class="rm-alerts__section">
|
|
239
|
+
<h3 v-if="section.label" class="rm-alerts__section-title">
|
|
240
|
+
{{ section.label }}
|
|
241
|
+
<span class="rm-alerts__section-count">{{ section.alerts.length }}</span>
|
|
242
|
+
</h3>
|
|
243
|
+
<RmAlertCard
|
|
244
|
+
v-for="alert in section.alerts"
|
|
245
|
+
:key="alert.id"
|
|
246
|
+
:alert="alert"
|
|
247
|
+
:menu="menu"
|
|
248
|
+
:lang="lang"
|
|
249
|
+
:on-watched-page="onWatchedPage"
|
|
250
|
+
:expanded="expandedId === alert.id"
|
|
251
|
+
:events="expandedId === alert.id ? expandedEvents : []"
|
|
252
|
+
:events-loading="expandedId === alert.id && expandedLoading"
|
|
253
|
+
@open="emit('open', $event)"
|
|
254
|
+
@rearm="emit('rearm', $event)"
|
|
255
|
+
@menu="emit('menu', $event)"
|
|
256
|
+
/>
|
|
257
|
+
</section>
|
|
258
|
+
</template>
|
|
227
259
|
</div>
|
|
228
260
|
|
|
229
261
|
<!-- Meme etat vide que les vues : cadre pointille, cloche teintee quand
|
|
@@ -26,6 +26,7 @@ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
26
26
|
import { PhCaretDown, PhCaretRight, PhCheck, PhMagnifyingGlass, PhMinus } from '@phosphor-icons/vue'
|
|
27
27
|
import type { Component } from 'vue'
|
|
28
28
|
import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
|
|
29
|
+
import { rmTreeCommit, rmTreeSettle } from '../utils/filterTree'
|
|
29
30
|
|
|
30
31
|
export interface RmTreeNode {
|
|
31
32
|
/** Ce qui part dans la selection. Unique dans tout l'arbre. */
|
|
@@ -161,7 +162,20 @@ const index = computed(() => {
|
|
|
161
162
|
const draft = ref(new Set<string>())
|
|
162
163
|
const expanded = ref(new Set<string>())
|
|
163
164
|
|
|
165
|
+
/**
|
|
166
|
+
* « Tout deselectionner » vide aussi ce que l'arbre ne montre pas : le
|
|
167
|
+
* prochain `commit` ne garde alors rien de cache (cf. rmTreeCommit).
|
|
168
|
+
*/
|
|
169
|
+
let dropHidden = false
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* L'arbre ne montre qu'une partie de la taxonomie : l'appelant cherche cote
|
|
173
|
+
* serveur et ne passe que les noeuds trouves (cf. `filterSearch`).
|
|
174
|
+
*/
|
|
175
|
+
const partial = computed(() => !props.filterSearch && search.value.trim() !== '')
|
|
176
|
+
|
|
164
177
|
function resetDraft() {
|
|
178
|
+
dropHidden = false
|
|
165
179
|
draft.value = new Set(selected.value)
|
|
166
180
|
// Les branches qui portent la selection s'ouvrent : arriver sur un arbre
|
|
167
181
|
// replie alors qu'il est filtre ne dit pas sur quoi.
|
|
@@ -203,12 +217,7 @@ const settleOrder = computed(() =>
|
|
|
203
217
|
)
|
|
204
218
|
|
|
205
219
|
function settle() {
|
|
206
|
-
settleOrder.value.
|
|
207
|
-
if (!node.children?.length) return
|
|
208
|
-
const all = node.children.every(child => draft.value.has(child.value))
|
|
209
|
-
if (all) draft.value.add(node.value)
|
|
210
|
-
else draft.value.delete(node.value)
|
|
211
|
-
})
|
|
220
|
+
rmTreeSettle(settleOrder.value, draft.value, partial.value)
|
|
212
221
|
}
|
|
213
222
|
|
|
214
223
|
function toggle(value: string) {
|
|
@@ -368,6 +377,7 @@ watch(isOpen, async (open) => {
|
|
|
368
377
|
|
|
369
378
|
function clear() {
|
|
370
379
|
draft.value = new Set()
|
|
380
|
+
dropHidden = true
|
|
371
381
|
}
|
|
372
382
|
|
|
373
383
|
/**
|
|
@@ -376,7 +386,8 @@ function clear() {
|
|
|
376
386
|
* selections identiques donnent la meme liste.
|
|
377
387
|
*/
|
|
378
388
|
function commit() {
|
|
379
|
-
const values =
|
|
389
|
+
const values = rmTreeCommit(index.value.keys(), draft.value, selected.value, !dropHidden)
|
|
390
|
+
dropHidden = false
|
|
380
391
|
selected.value = values
|
|
381
392
|
emit('apply', values)
|
|
382
393
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selection de RmFilterTree, hors du composant pour pouvoir la tester.
|
|
3
|
+
*
|
|
4
|
+
* Deux regles comptent quand l'arbre affiche n'est qu'une partie de la
|
|
5
|
+
* taxonomie, ce qui arrive des que l'appelant cherche cote serveur
|
|
6
|
+
* (`filterSearch` a faux) : il ne passe alors que les noeuds trouves.
|
|
7
|
+
*/
|
|
8
|
+
/** Un noeud de l'index, reduit a ce que la remontee lit. */
|
|
9
|
+
export interface RmTreeSettleEntry {
|
|
10
|
+
node: {
|
|
11
|
+
value: string;
|
|
12
|
+
children?: {
|
|
13
|
+
value: string;
|
|
14
|
+
}[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* La selection a ecrire dans le modele.
|
|
19
|
+
*
|
|
20
|
+
* Les valeurs affichees suivent le brouillon, dans l'ordre de l'arbre. Celles
|
|
21
|
+
* que l'arbre ne montre pas (cochees lors d'une recherche precedente) sont
|
|
22
|
+
* gardees telles quelles : l'arbre ne sait rien d'elles, il n'a pas a les
|
|
23
|
+
* retirer. Sans cette regle, cocher un code apres une nouvelle recherche
|
|
24
|
+
* effacait tous ceux choisis avant.
|
|
25
|
+
*
|
|
26
|
+
* `keepHidden` a faux pour « Tout deselectionner », qui vide tout.
|
|
27
|
+
*/
|
|
28
|
+
export declare function rmTreeCommit(shown: Iterable<string>, draft: Set<string>, previous: string[], keepHidden?: boolean): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Remonte la coherence apres un clic : un parent est decoche des qu'il lui
|
|
31
|
+
* manque un enfant, et coche quand il les a tous.
|
|
32
|
+
*
|
|
33
|
+
* `partial` : l'arbre ne montre qu'une partie des enfants (recherche cote
|
|
34
|
+
* serveur). Avoir coche tous les enfants AFFICHES ne veut alors pas dire avoir
|
|
35
|
+
* coche la branche : le parent n'est plus coche d'office, sans quoi chercher
|
|
36
|
+
* « C500 » et le cocher cochait aussi « C50 », et la selection annoncait tout
|
|
37
|
+
* le chapitre. Cocher le parent lui-meme reste possible.
|
|
38
|
+
*/
|
|
39
|
+
export declare function rmTreeSettle(order: RmTreeSettleEntry[], draft: Set<string>, partial?: boolean): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function rmTreeCommit(shown, draft, previous, keepHidden = true) {
|
|
2
|
+
const known = new Set(shown);
|
|
3
|
+
const hidden = keepHidden ? previous.filter((value) => !known.has(value)) : [];
|
|
4
|
+
const kept = [...known].filter((value) => draft.has(value));
|
|
5
|
+
return [...hidden, ...kept.filter((value) => !hidden.includes(value))];
|
|
6
|
+
}
|
|
7
|
+
export function rmTreeSettle(order, draft, partial = false) {
|
|
8
|
+
order.forEach(({ node }) => {
|
|
9
|
+
if (!node.children?.length) return;
|
|
10
|
+
const all = node.children.every((child) => draft.has(child.value));
|
|
11
|
+
if (!all) draft.delete(node.value);
|
|
12
|
+
else if (!partial) draft.add(node.value);
|
|
13
|
+
});
|
|
14
|
+
}
|