Skip to content

Commit c800782

Browse files
committed
Implement lifecycle and identity log dialogs with loading indicators and dynamic state handling
1 parent 8d43019 commit c800782

File tree

5 files changed

+252
-22
lines changed

5 files changed

+252
-22
lines changed

src/app.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@
44
<NuxtPage />
55
</NuxtLayout>
66
</template>
7+
8+
<script lang="ts" setup>
9+
const $route = useRoute()
10+
11+
if (/1|yes|on|true/.test($route.query.embedded as string)) {
12+
setPageLayout('empty')
13+
}
14+
</script>

src/components/identityForm/actions.vue

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,39 @@ div.flex
4444
q-btn.q-mx-xs(v-if="props.identity?._id" @click="sync" color="orange-8" :disabled="props.identity.state != IdentityState.TO_VALIDATE" icon="mdi-sync")
4545
q-tooltip.text-body2(slot="trigger" v-if="props.identity.state == IdentityState.TO_VALIDATE") Synchroniser l'identité
4646
q-tooltip.text-body2(slot="trigger" v-else) L'état de l'identité ne permet pas de la synchroniser
47-
q-btn.q-mx-xs(v-if="props.identity?._id" color="grey-8" icon="mdi-file-document" :href="'/jobs?filters[:concernedTo.id]=' + props.identity?._id" target="_blank")
47+
48+
q-btn.q-mx-xs(v-if="props.identity?._id" @click.prevent="dialogLog = true" color="grey-8" icon="mdi-file-document" :href="'/jobs?filters[:concernedTo.id]=' + props.identity?._id" target="_blank")
4849
q-tooltip.text-body2(slot="trigger") Voir les logs de l'identité
50+
q-dialog(v-model="dialogLog" full-height full-width persistent)
51+
q-card
52+
q-toolbar.absolute.bg-purple.text-white(dense)
53+
q-toolbar-title Journaux de l'identité {{ props.identity?.inetOrgPerson?.cn }}
54+
q-btn(icon="mdi-close" @click="dialogLog = false" dense flat)
55+
object.absolute.full-width(
56+
type="text/html"
57+
:data="'/jobs?filters[:concernedTo.id]=' + props.identity?._id + '&embedded=1'"
58+
style="height: calc(100% - 56px); margin-top: 50px; z-index: 1;"
59+
)
60+
.fit.items-center.column.justify-center
61+
q-circular-progress(indeterminate size='80px')
62+
span.q-mt-md Chargement en cours ...
63+
64+
q-btn.q-mx-xs(v-if="props.identity?._id" @click.prevent="dialogLifecycle = true" color="purple-8" icon="mdi-clock" :href="'/lifecycles/' + props.identity?._id" target="_blank")
65+
q-tooltip.text-body2(slot="trigger") Voir le cycle de vie de l'identité
66+
q-dialog(v-model="dialogLifecycle" full-height full-width persistent)
67+
q-card
68+
q-toolbar.absolute.bg-purple.text-white(dense)
69+
q-toolbar-title Cycle de vie de l'identité {{ props.identity?.inetOrgPerson?.cn }}
70+
q-btn(icon="mdi-close" @click="dialogLifecycle = false" dense flat)
71+
object.absolute.full-width(
72+
type="text/html"
73+
:data="'/lifecycles/' + props.identity?._id + '?embedded=1'"
74+
style="height: calc(100% - 56px); margin-top: 50px; z-index: 1;"
75+
)
76+
.fit.items-center.column.justify-center
77+
q-circular-progress(indeterminate size='80px')
78+
span.q-mt-md Chargement en cours ...
79+
4980
q-btn.q-mx-xs(v-if="props.identity?._id" @click="deleteIdentity" color="negative" icon="mdi-delete")
5081
q-tooltip.text-body2(slot="trigger") Supprimer l'identité
5182
q-dialog(v-model="resetPasswordModal" persistent medium)
@@ -107,6 +138,9 @@ const emits = defineEmits(['submit', 'sync', 'logs', 'create', 'delete'])
107138
108139
const validationsModal = ref(false)
109140
141+
const dialogLog = ref(false)
142+
const dialogLifecycle = ref(false)
143+
110144
async function doChangePassword() {
111145
const requestOptions = { method: 'POST', body: JSON.stringify({ id: props.identity._id, newPassword: newpassword.value }) }
112146
try {

src/layouts/empty.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<template lang="pug">
2+
q-layout(view="hHh LpR lff" style="margin-top: -1px;")
3+
q-page-container
4+
nuxt-page
5+
</template>

src/pages/jobs/index.vue

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ div
1515
template(#loading)
1616
.row.justify-center.q-my-md
1717
q-spinner-dots(color="primary" size="40px")
18+
//- q-timeline-entry.text-h5(icon='mdi-flag' title='Début de la liste des journaux' color="green")
1819
1920
template(v-for="(day, keyCompute) in computedJobsByDays" :key="keyCompute")
2021
q-timeline-entry.text-h5(
@@ -62,6 +63,7 @@ div
6263
pre(v-html="JSON.stringify(job.params, null, 2)")
6364
q-tab-panel(name="result")
6465
pre(v-html="JSON.stringify(job.result, null, 2)")
66+
q-timeline-entry.text-h5(v-if='empty' icon='mdi-flag-off' title='Fin de la liste...' color="red")
6567
</template>
6668

6769
<script lang="ts" setup>
@@ -82,22 +84,22 @@ div
8284
const scrollTargetRef = ref(null)
8385
const tabs = ref([])
8486
85-
const $route = useRoute();
86-
const $router = useRouter();
87-
const $dayjs = useDayjs();
87+
const $route = useRoute()
88+
const $router = useRouter()
89+
const $dayjs = useDayjs()
8890
89-
const offset = ref(0);
91+
const offset = ref(0)
9092
const query = computed(() => {
9193
return {
9294
limit: 10,
9395
skip: offset.value * 10,
9496
'sort[metadata.lastUpdatedAt]': 'desc',
9597
...$route.query,
96-
};
97-
});
98+
}
99+
})
98100
99101
const jobsBy = computed({
100-
get: () => $route.query.jobsBy ? `${$route.query.jobsBy}` : undefined,
102+
get: () => ($route.query.jobsBy ? `${$route.query.jobsBy}` : undefined),
101103
set: (value) => {
102104
tabs.value = [] // Reset tabs when changing jobsBy
103105
$router.replace({
@@ -119,8 +121,8 @@ const jobsByOptions = [
119121
{ label: 'Année', value: 'YYYY' },
120122
]
121123
122-
123-
const jobs = ref<any>([]);
124+
const empty = ref(false)
125+
const jobs = ref<any>([])
124126
125127
const computedJobsByDays = computed(() => {
126128
const jobsByDays = {}
@@ -132,33 +134,39 @@ const computedJobsByDays = computed(() => {
132134
jobsByDays[day].push(job)
133135
})
134136
return jobsByDays
135-
});
137+
})
136138
137139
const load = async (index, done) => {
138-
offset.value = index - 1;
140+
offset.value = index - 1
139141
const { data, pending, error, refresh } = await useHttp<any>(`/core/jobs/`, {
140142
method: 'GET',
141143
query,
142-
});
144+
})
143145
144-
jobs.value.push(...data.value.data);
145-
done(data.value.data.length === 0);
146+
jobs.value.push(...data.value.data)
147+
empty.value = data.value.data.length === 0
148+
done(data.value.data.length === 0)
146149
}
147-
function getColorState(state){
148-
switch(state){
150+
151+
function getColorState(state) {
152+
switch (state) {
149153
case -1:
150154
return 'negative'
151155
case 9:
152156
return 'positive'
157+
default:
158+
return 'primary'
153159
}
154-
return 'primary'
155160
}
156-
function getIconState(state){
157-
switch(state){
161+
162+
function getIconState(state) {
163+
switch (state) {
158164
case -1:
159-
return "mdi-account-remove"
165+
return 'mdi-account-remove'
160166
case 9:
161-
return "mdi-account-check"
167+
return 'mdi-account-check'
168+
default:
169+
return 'mdi-help'
162170
}
163171
}
164172
</script>

src/pages/lifecycles/[_id].vue

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<template lang="pug">
2+
div
3+
.q-px-md.row
4+
q-space
5+
q-select.col-4(
6+
v-model="lifecyclesBy"
7+
:options="lifecyclesByOptions"
8+
label="Regrouper par"
9+
emit-value
10+
map-options
11+
)
12+
//- sesame-searchfilters(:fields="fieldsList")
13+
q-timeline.q-px-lg
14+
q-infinite-scroll.q-px-lg(@load="load" :offset="250")
15+
template(#loading)
16+
.row.justify-center.q-my-md
17+
q-spinner-dots(color="primary" size="40px")
18+
//- q-timeline-entry.text-h5(icon='mdi-flag' title='Début du cycle de vie' color="green")
19+
20+
template(v-for="(day, keyCompute) in computedLifecyclesByDays" :key="keyCompute")
21+
q-timeline-entry.text-h5(
22+
23+
)
24+
time(v-text="keyCompute")
25+
q-timeline-entry(
26+
v-for="(lifecycle, key) in day" :key="key"
27+
:icon="getIconState(lifecycle.lifecycle)" :color="getColorState(lifecycle.lifecycle)"
28+
)
29+
template(#title)
30+
span(v-text="'[' + lifecycle._id + ']'")
31+
| &nbsp; - &nbsp;
32+
span(v-text="lifecycle.refId?.inetOrgPerson?.cn")
33+
| &nbsp; (
34+
small(v-text="lifecycle.refId?.inetOrgPerson?.uid")
35+
| )
36+
template(#subtitle)
37+
q-toolbar(dense)
38+
q-space
39+
q-icon(name="mdi-clock" size="20px" left)
40+
time(v-text="$dayjs(lifecycle.metadata?.createdAt).format('DD/MM/YYYY HH:mm:ss').toString()")
41+
q-card.q-pa-md.text-center(flat)
42+
p.q-mb-none.text-body1 {{ getLifecycleText(lifecycle.lifecycle) }}
43+
//- pre(v-html="JSON.stringify(lifecycle, null, 2)")
44+
q-timeline-entry.text-h5(v-if='empty' icon='mdi-flag-off' title='Fin de la liste...' color="red")
45+
</template>
46+
47+
<script lang="ts" setup>
48+
import { IdentityLifecycle } from '~/composables/useIdentityLifecycle'
49+
50+
// definePageMeta({
51+
// layout: 'empty',
52+
// })
53+
54+
const scrollTargetRef = ref(null)
55+
const tabs = ref([])
56+
57+
const $route = useRoute()
58+
const $router = useRouter()
59+
const $dayjs = useDayjs()
60+
61+
const offset = ref(0)
62+
const query = computed(() => {
63+
return {
64+
limit: 10,
65+
skip: offset.value * 10,
66+
'sort[metadata.lastUpdatedAt]': 'desc',
67+
...$route.query,
68+
}
69+
})
70+
71+
const lifecyclesBy = computed({
72+
get: () => ($route.query.lifecyclesBy ? `${$route.query.lifecyclesBy}` : undefined),
73+
set: (value) => {
74+
$router.replace({
75+
query: {
76+
...$route.query,
77+
lifecyclesBy: value,
78+
},
79+
})
80+
},
81+
})
82+
if (!lifecyclesBy.value) {
83+
console.log('lifecyclesBy.value', lifecyclesBy.value)
84+
lifecyclesBy.value = 'DD/MM/YYYY'
85+
}
86+
87+
const lifecyclesByOptions = [
88+
{ label: 'Jour', value: 'DD/MM/YYYY' },
89+
{ label: 'Mois', value: 'MM/YYYY' },
90+
{ label: 'Année', value: 'YYYY' },
91+
]
92+
93+
const empty = ref(false)
94+
const lifecycles = ref<any>([])
95+
96+
const computedLifecyclesByDays = computed(() => {
97+
const lifecyclesByDays = {}
98+
lifecycles.value.forEach((job) => {
99+
const day = $dayjs(job.metadata?.createdAt).format(lifecyclesBy.value)
100+
if (!lifecyclesByDays[day]) {
101+
lifecyclesByDays[day] = []
102+
}
103+
lifecyclesByDays[day].push(job)
104+
})
105+
return lifecyclesByDays
106+
})
107+
108+
const _id = $route.params._id as string
109+
110+
const load = async (index, done) => {
111+
offset.value = index - 1
112+
const { data, pending, error, refresh } = await useHttp<any>(`/management/lifecycle/identity/${_id}`, {
113+
method: 'GET',
114+
query,
115+
})
116+
117+
lifecycles.value.push(...data.value.data)
118+
empty.value = data.value.data.length === 0
119+
done(data.value.data.length === 0)
120+
}
121+
function getColorState(lifecycle) {
122+
switch (lifecycle) {
123+
case IdentityLifecycle.DELETED:
124+
return 'negative'
125+
case IdentityLifecycle.WAIT:
126+
return 'warning'
127+
case IdentityLifecycle.OFFICIAL:
128+
return 'info'
129+
case IdentityLifecycle.ACTIVE:
130+
return 'positive'
131+
case IdentityLifecycle.PROVISIONAL:
132+
return 'purple'
133+
case IdentityLifecycle.INACTIVE:
134+
return 'grey'
135+
default:
136+
return 'primary'
137+
}
138+
}
139+
function getIconState(lifecycle) {
140+
switch (lifecycle) {
141+
case IdentityLifecycle.DELETED:
142+
return 'mdi-account-remove'
143+
case IdentityLifecycle.WAIT:
144+
return 'mdi-clock-outline'
145+
case IdentityLifecycle.OFFICIAL:
146+
return 'mdi-circle'
147+
case IdentityLifecycle.ACTIVE:
148+
return 'mdi-emoticon'
149+
case IdentityLifecycle.PROVISIONAL:
150+
return 'mdi-human-queue'
151+
case IdentityLifecycle.INACTIVE:
152+
return 'mdi-power-sleep'
153+
default:
154+
return 'mdi-help'
155+
}
156+
}
157+
function getLifecycleText(lifecycle) {
158+
switch (lifecycle) {
159+
case IdentityLifecycle.DELETED:
160+
return 'Le compte est supprimer !'
161+
case IdentityLifecycle.WAIT:
162+
return 'Le compte est en attente de validation !'
163+
case IdentityLifecycle.OFFICIAL:
164+
return 'Le compte est officiel !'
165+
case IdentityLifecycle.ACTIVE:
166+
return 'Le compte est actif !'
167+
case IdentityLifecycle.PROVISIONAL:
168+
return 'Le compte est provisoire !'
169+
case IdentityLifecycle.INACTIVE:
170+
return 'Le compte est inactif !'
171+
default:
172+
return 'Impossible de récupérer le cycle de vie actuel !'
173+
}
174+
}
175+
</script>

0 commit comments

Comments
 (0)