chenged display of devices according to user`s role. all changes are made in backend

This commit is contained in:
tdv
2025-09-04 19:09:14 +03:00
parent c38dd658f5
commit 615abf42d2
16 changed files with 419 additions and 7 deletions

View File

@@ -20,6 +20,7 @@
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.6",
"uuid": "^11.1.0",
"vaul-vue": "^0.4.1",
"vue": "^3.5.17",
"vue-router": "^4.5.1"
},
@@ -2624,6 +2625,114 @@
"uuid": "dist/esm/bin/uuid"
}
},
"node_modules/vaul-vue": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/vaul-vue/-/vaul-vue-0.4.1.tgz",
"integrity": "sha512-A6jOWOZX5yvyo1qMn7IveoWN91mJI5L3BUKsIwkg6qrTGgHs1Sb1JF/vyLJgnbN1rH4OOOxFbtqL9A46bOyGUQ==",
"dependencies": {
"@vueuse/core": "^10.8.0",
"reka-ui": "^2.0.0",
"vue": "^3.4.5"
},
"peerDependencies": {
"reka-ui": "^2.0.0",
"vue": "^3.3.0"
}
},
"node_modules/vaul-vue/node_modules/@types/web-bluetooth": {
"version": "0.0.20",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
"license": "MIT"
},
"node_modules/vaul-vue/node_modules/@vueuse/core": {
"version": "10.11.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz",
"integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.20",
"@vueuse/metadata": "10.11.1",
"@vueuse/shared": "10.11.1",
"vue-demi": ">=0.14.8"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/vaul-vue/node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/vaul-vue/node_modules/@vueuse/metadata": {
"version": "10.11.1",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz",
"integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/vaul-vue/node_modules/@vueuse/shared": {
"version": "10.11.1",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz",
"integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==",
"license": "MIT",
"dependencies": {
"vue-demi": ">=0.14.8"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/vaul-vue/node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/vite": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz",

View File

@@ -21,6 +21,7 @@
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.6",
"uuid": "^11.1.0",
"vaul-vue": "^0.4.1",
"vue": "^3.5.17",
"vue-router": "^4.5.1"
},

View File

@@ -0,0 +1,22 @@
<script lang="ts" setup>
import type { DrawerRootEmits, DrawerRootProps } from "vaul-vue"
import { useForwardPropsEmits } from "reka-ui"
import { DrawerRoot } from "vaul-vue"
const props = withDefaults(defineProps<DrawerRootProps>(), {
shouldScaleBackground: true,
})
const emits = defineEmits<DrawerRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DrawerRoot
data-slot="drawer"
v-bind="forwarded"
>
<slot />
</DrawerRoot>
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts" setup>
import type { DrawerCloseProps } from "vaul-vue"
import { DrawerClose } from "vaul-vue"
const props = defineProps<DrawerCloseProps>()
</script>
<template>
<DrawerClose
data-slot="drawer-close"
v-bind="props"
>
<slot />
</DrawerClose>
</template>

View File

@@ -0,0 +1,34 @@
<script lang="ts" setup>
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { useForwardPropsEmits } from "reka-ui"
import { DrawerContent, DrawerPortal } from "vaul-vue"
import { cn } from "@/lib/utils"
import DrawerOverlay from "./DrawerOverlay.vue"
const props = defineProps<DialogContentProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DialogContentEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DrawerPortal>
<DrawerOverlay />
<DrawerContent
data-slot="drawer-content"
v-bind="forwarded"
:class="cn(
`group/drawer-content bg-background fixed z-50 flex h-auto flex-col`,
`data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg`,
`data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg`,
`data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:sm:max-w-sm`,
`data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:sm:max-w-sm`,
props.class,
)"
>
<div class="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
<slot />
</DrawerContent>
</DrawerPortal>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import type { DrawerDescriptionProps } from "vaul-vue"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DrawerDescription } from "vaul-vue"
import { cn } from "@/lib/utils"
const props = defineProps<DrawerDescriptionProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DrawerDescription
data-slot="drawer-description"
v-bind="delegatedProps"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</DrawerDescription>
</template>

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div
data-slot="drawer-footer"
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)"
>
<slot />
</div>
</template>

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div
data-slot="drawer-header"
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
>
<slot />
</div>
</template>

View File

@@ -0,0 +1,19 @@
<script lang="ts" setup>
import type { DialogOverlayProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DrawerOverlay } from "vaul-vue"
import { cn } from "@/lib/utils"
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DrawerOverlay
data-slot="drawer-overlay"
v-bind="delegatedProps"
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
/>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import type { DrawerTitleProps } from "vaul-vue"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DrawerTitle } from "vaul-vue"
import { cn } from "@/lib/utils"
const props = defineProps<DrawerTitleProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DrawerTitle
data-slot="drawer-title"
v-bind="delegatedProps"
:class="cn('text-foreground font-semibold', props.class)"
>
<slot />
</DrawerTitle>
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts" setup>
import type { DrawerTriggerProps } from "vaul-vue"
import { DrawerTrigger } from "vaul-vue"
const props = defineProps<DrawerTriggerProps>()
</script>
<template>
<DrawerTrigger
data-slot="drawer-trigger"
v-bind="props"
>
<slot />
</DrawerTrigger>
</template>

View File

@@ -0,0 +1,9 @@
export { default as Drawer } from "./Drawer.vue"
export { default as DrawerClose } from "./DrawerClose.vue"
export { default as DrawerContent } from "./DrawerContent.vue"
export { default as DrawerDescription } from "./DrawerDescription.vue"
export { default as DrawerFooter } from "./DrawerFooter.vue"
export { default as DrawerHeader } from "./DrawerHeader.vue"
export { default as DrawerOverlay } from "./DrawerOverlay.vue"
export { default as DrawerTitle } from "./DrawerTitle.vue"
export { default as DrawerTrigger } from "./DrawerTrigger.vue"