mountain-ui 1.0.109 → 1.0.111
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/index.d.ts +29 -0
- package/index.js +29 -0
- package/package.json +1 -1
- package/src/lib/registry/navigationRegistry/components/NavigationGroupRow.svelte +30 -32
- package/src/lib/registry/navigationRegistry/components/NewNavbarGroupDialog.svelte +43 -39
- package/src/lib/registry/navigationRegistry/registerNavigation.js +1 -3
- package/src/lib/registry/projectRegistry/createProject.js +2 -0
- package/src/lib/registry/widgetGroupRegistry/components/EmptySlot.svelte +47 -0
- package/src/lib/registry/widgetGroupRegistry/components/GroupPreview.svelte +142 -0
- package/src/lib/registry/widgetGroupRegistry/components/NewWidgetGroup.svelte +122 -0
- package/src/lib/registry/widgetGroupRegistry/components/WidgetGroup.svelte +39 -0
- package/src/lib/registry/widgetGroupRegistry/createWidget.js +17 -0
- package/src/lib/registry/widgetGroupRegistry/createWidgetGroup.js +19 -0
- package/src/lib/registry/widgetGroupRegistry/registerWidgetGroups.js +37 -0
- package/src/lib/registry/widgetGroupRegistry/registry.svelte.js +47 -0
- package/src/lib/registry/widgetTypeRegistry/components/CreateWidgetDialog.svelte +25 -0
- package/src/lib/registry/widgetTypeRegistry/components/Widget.svelte +18 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetConfig.svelte +16 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetPreview.svelte +59 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeButton.svelte +20 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeSelector.svelte +32 -0
- package/src/lib/registry/widgetTypeRegistry/createWidgetType.js +20 -0
- package/src/lib/registry/widgetTypeRegistry/registerWidgetTypes.js +14 -0
- package/src/lib/registry/widgetTypeRegistry/registry.svelte.js +43 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/Bar.svelte +79 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/ConfigBar.svelte +176 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/index.js +13 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/text.js +21 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/ConfigEvolution.svelte +180 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/Evolution.svelte +81 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/index.js +13 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/text.js +21 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/ConfigKPI.svelte +201 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/KPI.svelte +118 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/index.js +12 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/text.js +22 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/ConfigList.svelte +199 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/List.svelte +97 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/index.js +12 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/text.js +21 -0
- package/src/routes/exemple/[project_normalized_name]/+layout.svelte +1 -1
- package/src/routes/exemple/[project_normalized_name]/home/+page.svelte +61 -1
- package/src/routes/exemple/[project_normalized_name]/navigation/+page.svelte +28 -0
- package/src/routes/exemple/[project_normalized_name]/widgets/+page.svelte +92 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Button, DropdownMenu, Input, sendRequest } from 'hamzus-ui';
|
|
3
|
+
import { frequencyText, frequencyTextForConfig } from './text';
|
|
4
|
+
import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
|
|
5
|
+
|
|
6
|
+
let {id = null, save = () => {}} = $props()
|
|
7
|
+
|
|
8
|
+
let title = $state('');
|
|
9
|
+
|
|
10
|
+
const entities = entityRegistry.getAll()
|
|
11
|
+
|
|
12
|
+
let entityId = $state(null);
|
|
13
|
+
const entity = $derived(entityRegistry.get(entityId));
|
|
14
|
+
|
|
15
|
+
let frequency = $state('month'); // day | month | year
|
|
16
|
+
const frequencies = ['day', 'month', 'year'];
|
|
17
|
+
|
|
18
|
+
let valueFieldId = $state(null);
|
|
19
|
+
const valueField = $derived(entityRegistry.getField(valueFieldId));
|
|
20
|
+
|
|
21
|
+
let dateFieldId = $state(null);
|
|
22
|
+
const dateField = $derived(entityRegistry.getField(dateFieldId));
|
|
23
|
+
const dateFieldTypes = ['time-created_at', 'time-datetime', 'time-updated_at'];
|
|
24
|
+
|
|
25
|
+
let operation = 'count'; // count | sum | avg | min | max
|
|
26
|
+
const operations = ['count', 'sum', 'avg', 'min', 'max'];
|
|
27
|
+
|
|
28
|
+
function handleSelectEntity(entity) {
|
|
29
|
+
entityId = entity.id;
|
|
30
|
+
|
|
31
|
+
// parcourir les fields pour set auto le field de value et de date
|
|
32
|
+
for (const field of entity.fields) {
|
|
33
|
+
if (field.type.startsWith('number-') || field.type.startsWith('calculation-')) {
|
|
34
|
+
valueFieldId = field.id;
|
|
35
|
+
}
|
|
36
|
+
if (dateFieldTypes.includes(field.type)) {
|
|
37
|
+
dateFieldId = field.id;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function handleSave() {
|
|
43
|
+
save({
|
|
44
|
+
id,
|
|
45
|
+
title,
|
|
46
|
+
entityId,
|
|
47
|
+
frequency,
|
|
48
|
+
valueFieldId,
|
|
49
|
+
dateFieldId,
|
|
50
|
+
operation
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<div class="config">
|
|
56
|
+
<Input label="titre" bind:value={title} placeholder="exemple"></Input>
|
|
57
|
+
<h5>Entité</h5>
|
|
58
|
+
<DropdownMenu.Root direction="bottom">
|
|
59
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
60
|
+
<Button variant="secondary">
|
|
61
|
+
<h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
|
|
62
|
+
</Button>
|
|
63
|
+
</DropdownMenu.Trigger>
|
|
64
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
65
|
+
{#each $entities as entity}
|
|
66
|
+
<Button
|
|
67
|
+
onClick={() => {
|
|
68
|
+
handleSelectEntity(entity);
|
|
69
|
+
}}
|
|
70
|
+
variant="ghost"
|
|
71
|
+
style="width:100%;"><h5>{entity.plural_name}</h5></Button
|
|
72
|
+
>
|
|
73
|
+
{/each}
|
|
74
|
+
</DropdownMenu.Content>
|
|
75
|
+
</DropdownMenu.Root>
|
|
76
|
+
{#if entity}
|
|
77
|
+
{@const availedValueFields = entity.fields.filter(
|
|
78
|
+
(field) => field.type.startsWith('number-') || field.type.startsWith('calculation-')
|
|
79
|
+
)}
|
|
80
|
+
{@const availedDateFields = entity.fields.filter((field) =>
|
|
81
|
+
dateFieldTypes.includes(field.type)
|
|
82
|
+
)}
|
|
83
|
+
<h5>Champs pour valeurs</h5>
|
|
84
|
+
<DropdownMenu.Root direction="bottom">
|
|
85
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
86
|
+
<Button variant="secondary">
|
|
87
|
+
<h5>{valueField?.name ?? 'choisissez un champ pour valeur'}</h5>
|
|
88
|
+
</Button>
|
|
89
|
+
</DropdownMenu.Trigger>
|
|
90
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
91
|
+
{#if availedValueFields.length > 0}
|
|
92
|
+
{#each availedValueFields as field}
|
|
93
|
+
<Button
|
|
94
|
+
onClick={() => {
|
|
95
|
+
valueFieldId = field.id;
|
|
96
|
+
}}
|
|
97
|
+
variant="ghost"
|
|
98
|
+
style="width:100%;"><h5>{field.name}</h5></Button
|
|
99
|
+
>
|
|
100
|
+
{/each}
|
|
101
|
+
{:else}
|
|
102
|
+
<div class="nothing">
|
|
103
|
+
<h3>Aucun champs de valeur disponible</h3>
|
|
104
|
+
<p>
|
|
105
|
+
L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
{/if}
|
|
109
|
+
</DropdownMenu.Content>
|
|
110
|
+
</DropdownMenu.Root>
|
|
111
|
+
<h5>Champs pour date</h5>
|
|
112
|
+
<DropdownMenu.Root direction="bottom">
|
|
113
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
114
|
+
<Button variant="secondary">
|
|
115
|
+
<h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
|
|
116
|
+
</Button>
|
|
117
|
+
</DropdownMenu.Trigger>
|
|
118
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
119
|
+
{#if availedDateFields.length > 0}
|
|
120
|
+
{#each availedDateFields as field}
|
|
121
|
+
<Button
|
|
122
|
+
onClick={() => {
|
|
123
|
+
dateFieldId = field.id;
|
|
124
|
+
}}
|
|
125
|
+
variant="ghost"
|
|
126
|
+
style="width:100%;"><h5>{field.name}</h5></Button
|
|
127
|
+
>
|
|
128
|
+
{/each}
|
|
129
|
+
{:else}
|
|
130
|
+
<div class="nothing">
|
|
131
|
+
<h3>Aucun champs de date disponible</h3>
|
|
132
|
+
<p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
|
|
133
|
+
</div>
|
|
134
|
+
{/if}
|
|
135
|
+
</DropdownMenu.Content>
|
|
136
|
+
</DropdownMenu.Root>
|
|
137
|
+
<h5>fréquence</h5>
|
|
138
|
+
<DropdownMenu.Root direction="bottom">
|
|
139
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
140
|
+
<Button variant="secondary">
|
|
141
|
+
<h5>{frequency ? frequencyTextForConfig[frequency] : 'choisissez une fréquence'}</h5>
|
|
142
|
+
</Button>
|
|
143
|
+
</DropdownMenu.Trigger>
|
|
144
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
145
|
+
{#each frequencies as frequencyEl}
|
|
146
|
+
<Button
|
|
147
|
+
onClick={() => {
|
|
148
|
+
frequency = frequencyEl;
|
|
149
|
+
}}
|
|
150
|
+
variant="ghost"
|
|
151
|
+
style="width:100%;"><h5>{frequencyTextForConfig[frequencyEl]}</h5></Button
|
|
152
|
+
>
|
|
153
|
+
{/each}
|
|
154
|
+
</DropdownMenu.Content>
|
|
155
|
+
</DropdownMenu.Root>
|
|
156
|
+
{/if}
|
|
157
|
+
|
|
158
|
+
<Button onClick={handleSave}>
|
|
159
|
+
<h5>enregistrer</h5>
|
|
160
|
+
</Button>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<style>
|
|
164
|
+
.config {
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
row-gap: var(--pad-m);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.nothing {
|
|
171
|
+
display: flex;
|
|
172
|
+
flex-direction: column;
|
|
173
|
+
row-gap: var(--pad-m);
|
|
174
|
+
padding: var(--pad-m);
|
|
175
|
+
}
|
|
176
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import ConfigBar from "./ConfigBar.svelte";
|
|
2
|
+
import Bar from "./Bar.svelte";
|
|
3
|
+
import { createWidgetType } from "../../createWidgetType";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export default createWidgetType({
|
|
7
|
+
type:"Bar",
|
|
8
|
+
name:"Graphique en bar",
|
|
9
|
+
components:{
|
|
10
|
+
config:ConfigBar,
|
|
11
|
+
component:Bar,
|
|
12
|
+
}
|
|
13
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export const frequencyText = {
|
|
4
|
+
'day': 'aujourd\'hui',
|
|
5
|
+
'month': 'ce mois-ci',
|
|
6
|
+
'year': 'cette année'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const frequencyTextForConfig = {
|
|
10
|
+
'day': 'par jour',
|
|
11
|
+
'month': 'par mois',
|
|
12
|
+
'year': 'par an'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const operationText = {
|
|
16
|
+
'count': 'nombre d\'entrée',
|
|
17
|
+
'sum': 'somme',
|
|
18
|
+
'avg': 'moyenne',
|
|
19
|
+
'min': "min",
|
|
20
|
+
'max': "max"
|
|
21
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Button, DropdownMenu, Input, sendRequest } from 'hamzus-ui';
|
|
3
|
+
import { frequencyText, frequencyTextForConfig } from './text';
|
|
4
|
+
import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
|
|
5
|
+
|
|
6
|
+
let {id = null, save = () => {}} = $props()
|
|
7
|
+
|
|
8
|
+
let title = $state('');
|
|
9
|
+
|
|
10
|
+
const entities = entityRegistry.getAll()
|
|
11
|
+
|
|
12
|
+
let entityId = $state(null);
|
|
13
|
+
const entity = $derived(entityRegistry.get(entityId));
|
|
14
|
+
|
|
15
|
+
let frequency = $state('month'); // day | month | year
|
|
16
|
+
const frequencies = ['day', 'month', 'year'];
|
|
17
|
+
|
|
18
|
+
let valueFieldId = $state(null);
|
|
19
|
+
const valueField = $derived(entityRegistry.getField(valueFieldId));
|
|
20
|
+
|
|
21
|
+
let dateFieldId = $state(null);
|
|
22
|
+
const dateField = $derived(entityRegistry.getField(dateFieldId));
|
|
23
|
+
const dateFieldTypes = ['time-created_at', 'time-datetime', 'time-updated_at'];
|
|
24
|
+
|
|
25
|
+
let operation = 'count'; // count | sum | avg | min | max
|
|
26
|
+
const operations = ['count', 'sum', 'avg', 'min', 'max'];
|
|
27
|
+
|
|
28
|
+
let size = $state('4/2');
|
|
29
|
+
const sizes = ['4/2', '6/2', '8/2', '12/2'];
|
|
30
|
+
|
|
31
|
+
function handleSelectEntity(entity) {
|
|
32
|
+
entityId = entity.id;
|
|
33
|
+
|
|
34
|
+
// parcourir les fields pour set auto le field de value et de date
|
|
35
|
+
for (const field of entity.fields) {
|
|
36
|
+
if (field.type.startsWith('number-') || field.type.startsWith('calculation-')) {
|
|
37
|
+
valueFieldId = field.id;
|
|
38
|
+
}
|
|
39
|
+
if (dateFieldTypes.includes(field.type)) {
|
|
40
|
+
dateFieldId = field.id;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function handleSave() {
|
|
46
|
+
save({
|
|
47
|
+
id,
|
|
48
|
+
title,
|
|
49
|
+
entityId,
|
|
50
|
+
frequency,
|
|
51
|
+
valueFieldId,
|
|
52
|
+
dateFieldId,
|
|
53
|
+
operation,
|
|
54
|
+
size
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<div class="config">
|
|
60
|
+
<Input label="titre" bind:value={title} placeholder="exemple"></Input>
|
|
61
|
+
<h5>Entité</h5>
|
|
62
|
+
<DropdownMenu.Root direction="bottom">
|
|
63
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
64
|
+
<Button variant="secondary">
|
|
65
|
+
<h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
|
|
66
|
+
</Button>
|
|
67
|
+
</DropdownMenu.Trigger>
|
|
68
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
69
|
+
{#each $entities as entity}
|
|
70
|
+
<Button
|
|
71
|
+
onClick={() => {
|
|
72
|
+
handleSelectEntity(entity);
|
|
73
|
+
}}
|
|
74
|
+
variant="ghost"
|
|
75
|
+
style="width:100%;"><h5>{entity.plural_name}</h5></Button
|
|
76
|
+
>
|
|
77
|
+
{/each}
|
|
78
|
+
</DropdownMenu.Content>
|
|
79
|
+
</DropdownMenu.Root>
|
|
80
|
+
{#if entity}
|
|
81
|
+
{@const availedValueFields = entity.fields.filter(
|
|
82
|
+
(field) => field.type.startsWith('number-') || field.type.startsWith('calculation-')
|
|
83
|
+
)}
|
|
84
|
+
{@const availedDateFields = entity.fields.filter((field) =>
|
|
85
|
+
dateFieldTypes.includes(field.type)
|
|
86
|
+
)}
|
|
87
|
+
<h5>Champs pour valeurs</h5>
|
|
88
|
+
<DropdownMenu.Root direction="bottom">
|
|
89
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
90
|
+
<Button variant="secondary">
|
|
91
|
+
<h5>{valueField?.name ?? 'choisissez un champ pour valeur'}</h5>
|
|
92
|
+
</Button>
|
|
93
|
+
</DropdownMenu.Trigger>
|
|
94
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
95
|
+
{#if availedValueFields.length > 0}
|
|
96
|
+
{#each availedValueFields as field}
|
|
97
|
+
<Button
|
|
98
|
+
onClick={() => {
|
|
99
|
+
valueFieldId = field.id;
|
|
100
|
+
}}
|
|
101
|
+
variant="ghost"
|
|
102
|
+
style="width:100%;"><h5>{field.name}</h5></Button
|
|
103
|
+
>
|
|
104
|
+
{/each}
|
|
105
|
+
{:else}
|
|
106
|
+
<div class="nothing">
|
|
107
|
+
<h3>Aucun champs de valeur disponible</h3>
|
|
108
|
+
<p>
|
|
109
|
+
L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
112
|
+
{/if}
|
|
113
|
+
</DropdownMenu.Content>
|
|
114
|
+
</DropdownMenu.Root>
|
|
115
|
+
<h5>Champs pour date</h5>
|
|
116
|
+
<DropdownMenu.Root direction="bottom">
|
|
117
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
118
|
+
<Button variant="secondary">
|
|
119
|
+
<h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
|
|
120
|
+
</Button>
|
|
121
|
+
</DropdownMenu.Trigger>
|
|
122
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
123
|
+
{#if availedDateFields.length > 0}
|
|
124
|
+
{#each availedDateFields as field}
|
|
125
|
+
<Button
|
|
126
|
+
onClick={() => {
|
|
127
|
+
dateFieldId = field.id;
|
|
128
|
+
}}
|
|
129
|
+
variant="ghost"
|
|
130
|
+
style="width:100%;"><h5>{field.name}</h5></Button
|
|
131
|
+
>
|
|
132
|
+
{/each}
|
|
133
|
+
{:else}
|
|
134
|
+
<div class="nothing">
|
|
135
|
+
<h3>Aucun champs de date disponible</h3>
|
|
136
|
+
<p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
|
|
137
|
+
</div>
|
|
138
|
+
{/if}
|
|
139
|
+
</DropdownMenu.Content>
|
|
140
|
+
</DropdownMenu.Root>
|
|
141
|
+
<h5>fréquence</h5>
|
|
142
|
+
<DropdownMenu.Root direction="bottom">
|
|
143
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
144
|
+
<Button variant="secondary">
|
|
145
|
+
<h5>{frequency ? frequencyTextForConfig[frequency] : 'choisissez une fréquence'}</h5>
|
|
146
|
+
</Button>
|
|
147
|
+
</DropdownMenu.Trigger>
|
|
148
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
149
|
+
{#each frequencies as frequencyEl}
|
|
150
|
+
<Button
|
|
151
|
+
onClick={() => {
|
|
152
|
+
frequency = frequencyEl;
|
|
153
|
+
}}
|
|
154
|
+
variant="ghost"
|
|
155
|
+
style="width:100%;"><h5>{frequencyTextForConfig[frequencyEl]}</h5></Button
|
|
156
|
+
>
|
|
157
|
+
{/each}
|
|
158
|
+
</DropdownMenu.Content>
|
|
159
|
+
</DropdownMenu.Root>
|
|
160
|
+
{/if}
|
|
161
|
+
|
|
162
|
+
<Button onClick={handleSave}>
|
|
163
|
+
<h5>enregistrer</h5>
|
|
164
|
+
</Button>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<style>
|
|
168
|
+
.config {
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
row-gap: var(--pad-m);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.nothing {
|
|
175
|
+
display: flex;
|
|
176
|
+
flex-direction: column;
|
|
177
|
+
row-gap: var(--pad-m);
|
|
178
|
+
padding: var(--pad-m);
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { ChartLine, sendRequest, Skeleton } from 'hamzus-ui';
|
|
3
|
+
import { frequencyText, operationText } from './text';
|
|
4
|
+
import { onMount } from 'svelte';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
id = '',title = '',entityId = '',frequency = '',valueFieldId = '',dateFieldId = '',operation = '',
|
|
8
|
+
} = $props()
|
|
9
|
+
|
|
10
|
+
let data = $state(null);
|
|
11
|
+
let previousTotal = $state(null);
|
|
12
|
+
|
|
13
|
+
onMount(async () => {
|
|
14
|
+
const request = await sendRequest({
|
|
15
|
+
path: '/get-widget-data',
|
|
16
|
+
data: {
|
|
17
|
+
widgetLinkId: id
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
data = request.data
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function getRandomSizes() {
|
|
26
|
+
const sizes = [60, 120, 80];
|
|
27
|
+
|
|
28
|
+
return sizes[Math.floor(Math.random() * sizes.length)];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getPercent() {
|
|
32
|
+
if (previousTotal === 0) {
|
|
33
|
+
if (total === 0) return 0;
|
|
34
|
+
return null; // augmentation non calculable
|
|
35
|
+
}
|
|
36
|
+
return ((total - previousTotal) / previousTotal) * 100;
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div class="kpi-container">
|
|
41
|
+
<div class="kpi">
|
|
42
|
+
<h4>{title}</h4>
|
|
43
|
+
{#if data === null}
|
|
44
|
+
<Skeleton style="width:{getRandomSizes()}px;height:32px;"></Skeleton>
|
|
45
|
+
{:else}
|
|
46
|
+
<ChartLine {data}
|
|
47
|
+
></ChartLine>
|
|
48
|
+
{/if}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<style>
|
|
53
|
+
.kpi-container {
|
|
54
|
+
width: 100%;
|
|
55
|
+
height: 100%;
|
|
56
|
+
padding: var(--pad-m);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.kpi {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
row-gap: var(--pad-m);
|
|
63
|
+
padding: var(--pad-xxl);
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
background-color: var(--bg-blur);
|
|
67
|
+
border-radius: var(--radius-m);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.bottom {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: space-between;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.right {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
column-gap: var(--pad-m);
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import ConfigEvolution from "./ConfigEvolution.svelte";
|
|
2
|
+
import Evolution from "./Evolution.svelte";
|
|
3
|
+
import { createWidgetType } from "../../createWidgetType";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export default createWidgetType({
|
|
7
|
+
type: "Evolution",
|
|
8
|
+
name: "Graphique d'évolution",
|
|
9
|
+
components: {
|
|
10
|
+
config: ConfigEvolution,
|
|
11
|
+
component: Evolution,
|
|
12
|
+
}
|
|
13
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export const frequencyText = {
|
|
4
|
+
'day': 'aujourd\'hui',
|
|
5
|
+
'month': 'ce mois-ci',
|
|
6
|
+
'year': 'cette année'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const frequencyTextForConfig = {
|
|
10
|
+
'day': 'par jour',
|
|
11
|
+
'month': 'par mois',
|
|
12
|
+
'year': 'par an'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const operationText = {
|
|
16
|
+
'count': 'nombre d\'entrée',
|
|
17
|
+
'sum': 'somme',
|
|
18
|
+
'avg': 'moyenne',
|
|
19
|
+
'min': "min",
|
|
20
|
+
'max': "max"
|
|
21
|
+
}
|