WIP: frontend module federation setup.

Initial work to accept future user related apps.
This commit is contained in:
Antoine Nguyen
2025-02-14 13:39:08 +01:00
parent 604a91caa9
commit afe3253fc8
13 changed files with 217 additions and 24 deletions
+3
View File
@@ -114,4 +114,7 @@ export default {
`${resource}/filtersets/${filterSetName}/filters/${filter}/`
)
},
getAvailableApplications() {
return repository.get(`${resource}/available_applications/`)
},
}
@@ -0,0 +1,3 @@
<template>
<v-btn icon="mdi-apps" flat> </v-btn>
</template>
+109
View File
@@ -0,0 +1,109 @@
<template>
<div class="top-menu">
<v-menu activator="parent" location="bottom">
<template #activator="{ props }">
<v-btn icon="mdi-apps" flat class="mr-4" v-bind="props"></v-btn>
</template>
<v-card min-width="350" max-width="400" class="pa-4">
<v-row class="justify-center">
<v-col
v-for="application in applications"
:key="application.name"
cols="6"
>
<v-sheet
rounded
class="application text-center pa-4 text-body-2"
@click="$router.push(application.url)"
>
<v-icon color="primary" :icon="application.icon" size="x-large" />
<div class="mt-2">{{ application.label }}</div>
</v-sheet>
</v-col>
</v-row>
</v-card>
</v-menu>
<v-btn icon flat color="primary">
{{ userInitials }}
<v-menu activator="parent" location="bottom">
<v-card min-width="300" max-width="350">
<v-list>
<div class="text-center">
<v-avatar color="primary">
<span class="text-h5">{{ userInitials }}</span>
</v-avatar>
<v-list-item :title="user.username" />
</div>
<v-divider></v-divider>
<template v-if="remote">
<v-list-item href="https://localhost:3000/account">
<template #prepend>
<v-icon icon="mdi-account-circle-outline"></v-icon>
</template>
<v-list-item-title>Account</v-list-item-title>
</v-list-item>
<v-list-item @click="logout">
<template #prepend>
<v-icon icon="mdi-logout"></v-icon>
</template>
<v-list-item-title>Logout</v-list-item-title>
</v-list-item>
</template>
</v-list>
</v-card>
</v-menu>
</v-btn>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue'
import { getActivePinia } from 'pinia'
import accountApi from '@/api/account'
const props = defineProps({
user: {
type: Object,
default: null,
},
remote: {
type: Boolean,
default: false,
},
})
const applications = ref([])
const userInitials = computed(() => {
return props.user.first_name && props.user.last_name
? `${props.user.first_name[0].toUpperCase()}${props.user.last_name[0].toUpperCase()}`
: props.user.username.slice(0, 2).toUpperCase()
})
async function logout() {
getActivePinia()._s.forEach(async (store) => await store.$reset())
}
onMounted(() => {
accountApi.getAvailableApplications().then((resp) => {
applications.value = resp.data
})
})
</script>
<style scoped lang="scss">
.top-menu {
position: fixed;
top: 10px;
right: 10px;
}
.application {
cursor: pointer;
}
.application:hover {
background-color: rgb(var(--v-theme-surface));
}
</style>
+2 -2
View File
@@ -1,5 +1,5 @@
<template>
<v-fab app icon flat location="top right" color="primary">
<v-btn icon flat color="primary">
{{ userInitials }}
<v-menu activator="parent" location="bottom">
<v-card min-width="300" max-width="350">
@@ -28,7 +28,7 @@
</v-list>
</v-card>
</v-menu>
</v-fab>
</v-btn>
</template>
<script setup>
+24 -2
View File
@@ -11,7 +11,7 @@
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
max-width="190"
class="logo"
@click="router.push({ name: 'Dashboard' })"
@click="router.push(props.logoRoute)"
/>
<v-btn
:icon="rail ? 'mdi-chevron-right' : 'mdi-chevron-left'"
@@ -24,8 +24,20 @@
<v-list nav>
<template v-for="item in menuItems" :key="item.text">
<template v-if="displayMenuItem(item)">
<v-list-subheader v-if="item.subheader">
{{ item.text.toUpperCase() }}
</v-list-subheader>
<v-list-item
v-if="!item.children"
v-else-if="item.action"
:value="item"
:exact="item.exact"
:title="item.text"
:prepend-icon="item.icon"
@click="item.action"
>
</v-list-item>
<v-list-item
v-else-if="!item.children"
:value="item"
:to="item.to"
link
@@ -124,6 +136,10 @@ const props = defineProps({
required: false,
default: null,
},
logoRoute: {
type: Object,
default: null,
},
})
const globalStore = useGlobalStore()
@@ -358,6 +374,12 @@ onMounted(() => {
}
}
.v-list-subheader {
&__text {
color: white !important;
}
}
.logo {
cursor: pointer;
}
+4 -1
View File
@@ -37,10 +37,13 @@ export default defineConfig({
name: 'coretools',
filename: 'remoteEntry.js',
exposes: {
'./api-repository': './src/api/repository.js',
'./auth-store': './src/stores/auth.store.js',
'./auth-callback': './src/views/login/LoginCallbackView.vue',
'./navbar': './src/layouts/dashboard/NavBar.vue',
'./user-menu': './src/components/shared/UserMenu.vue',
'./top-menu': './src/components/shared/TopMenu.vue',
'./menu-items': './src/components/tools/MenuItems.vue',
'./form-rules': './src/plugins/rules.js',
},
shared: ['vue', 'pinia', 'vue-router', 'vue3-gettext'],
}),