mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 21:33:02 +01:00
Compare commits
1 Commits
copilot/im
...
tonya/coll
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d6b17318 |
130
frontend/components/App/OrgSelector.vue
Normal file
130
frontend/components/App/OrgSelector.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<Popover v-model:open="open">
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
:aria-expanded="open"
|
||||
class="w-full justify-between"
|
||||
>
|
||||
{{ value && value.name ? value.name : "Select inventory" }}
|
||||
<div class="flex items-center gap-2" v-if="value">
|
||||
<Badge
|
||||
class="whitespace-nowrap"
|
||||
:variant="value.role === 'owner' ? 'default' : value.role === 'admin' ? 'secondary' : 'outline'"
|
||||
>
|
||||
{{ value.role }}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[--reka-popper-anchor-width] p-0">
|
||||
<Command :ignore-filter="true">
|
||||
<CommandInput v-model="search" placeholder="Search collections..." :display-value="(_) => ''" />
|
||||
<CommandEmpty>No inventory found</CommandEmpty>
|
||||
<CommandList>
|
||||
<CommandGroup heading="Your Collections">
|
||||
<CommandItem
|
||||
v-for="org in filteredOrgs"
|
||||
:key="org.id"
|
||||
:value="org.id"
|
||||
@select="selectOrg(org as unknown as OrgSummary)"
|
||||
>
|
||||
<Check :class="cn('mr-2 h-4 w-4', value?.id === org.id ? 'opacity-100' : 'opacity-0')" />
|
||||
<div class="flex w-full items-center justify-between gap-2">
|
||||
{{ org.name }}
|
||||
<div class="flex items-center gap-2">
|
||||
<Badge
|
||||
class="whitespace-nowrap"
|
||||
variant="outline"
|
||||
>
|
||||
{{ org.count }}
|
||||
</Badge>
|
||||
<Badge
|
||||
class="whitespace-nowrap"
|
||||
:variant="org.role === 'owner' ? 'default' : org.role === 'admin' ? 'secondary' : 'outline'"
|
||||
>
|
||||
{{ org.role }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandGroup>
|
||||
<CommandItem @select="() => {}">
|
||||
<Plus class="mr-2 size-4" /> Create New Collection
|
||||
</CommandItem>
|
||||
<CommandItem @select="() => {}">
|
||||
<Plus class="mr-2 size-4" /> Join Existing Collection
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Check, ChevronsUpDown, Lock, Users, Plus } from "lucide-vue-next";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "~/components/ui/command";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { useVModel } from "@vueuse/core";
|
||||
|
||||
type OrgSummary = {
|
||||
id: string;
|
||||
name: string;
|
||||
count: number;
|
||||
role: "owner" | "admin" | "editor" | "viewer";
|
||||
type: "personal" | "org";
|
||||
};
|
||||
|
||||
type Props = {
|
||||
modelValue?: OrgSummary | null;
|
||||
};
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const open = ref(false);
|
||||
const search = ref("");
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
|
||||
// Mock data for demonstration purposes
|
||||
const orgs = ref<OrgSummary[]>([
|
||||
{ id: "1", name: "Personal Inventory", count: 1, role: "owner", type: "personal" },
|
||||
{ id: "2", name: "Family Home", count: 4, role: "admin", type: "org" },
|
||||
{ id: "3", name: "Office Equipment", count: 12, role: "editor", type: "org" },
|
||||
{ id: "4", name: "Workshop Tools", count: 3, role: "viewer", type: "org" },
|
||||
]);
|
||||
|
||||
function selectOrg(org: OrgSummary) {
|
||||
if (value.value?.id !== org.id) {
|
||||
value.value = org;
|
||||
} else {
|
||||
value.value = null;
|
||||
}
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
const filteredOrgs = computed(() => {
|
||||
const filtered = fuzzysort.go(search.value, orgs.value, { key: "name", all: true }).map((i) => i.obj);
|
||||
return filtered;
|
||||
});
|
||||
|
||||
// Reset search when value is cleared
|
||||
watch(
|
||||
() => value.value,
|
||||
() => {
|
||||
if (!value.value) {
|
||||
search.value = "";
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -1,18 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue";
|
||||
import { Primitive, type PrimitiveProps } from "reka-ui";
|
||||
import { type ButtonVariants, buttonVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { HTMLAttributes } from "vue";
|
||||
import { Primitive, type PrimitiveProps } from "reka-ui";
|
||||
import { type ButtonVariants, buttonVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface Props extends PrimitiveProps {
|
||||
variant?: ButtonVariants["variant"];
|
||||
size?: ButtonVariants["size"];
|
||||
class?: HTMLAttributes["class"];
|
||||
}
|
||||
interface Props extends PrimitiveProps {
|
||||
variant?: ButtonVariants["variant"];
|
||||
size?: ButtonVariants["size"];
|
||||
class?: HTMLAttributes["class"];
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
as: "button",
|
||||
});
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
as: "button",
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
57
frontend/components/ui/calendar/Calendar.vue
Normal file
57
frontend/components/ui/calendar/Calendar.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useForwardPropsEmits } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNextButton, CalendarPrevButton } from '.'
|
||||
|
||||
const props = defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const emits = defineEmits<CalendarRootEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarRoot
|
||||
v-slot="{ grid, weekDays }"
|
||||
:class="cn('p-3', props.class)"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<CalendarHeader>
|
||||
<CalendarPrevButton />
|
||||
<CalendarHeading />
|
||||
<CalendarNextButton />
|
||||
</CalendarHeader>
|
||||
|
||||
<div class="flex flex-col gap-y-4 mt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0">
|
||||
<CalendarGrid v-for="month in grid" :key="month.value.toString()">
|
||||
<CalendarGridHead>
|
||||
<CalendarGridRow>
|
||||
<CalendarHeadCell
|
||||
v-for="day in weekDays" :key="day"
|
||||
>
|
||||
{{ day }}
|
||||
</CalendarHeadCell>
|
||||
</CalendarGridRow>
|
||||
</CalendarGridHead>
|
||||
<CalendarGridBody>
|
||||
<CalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="mt-2 w-full">
|
||||
<CalendarCell
|
||||
v-for="weekDate in weekDates"
|
||||
:key="weekDate.toString()"
|
||||
:date="weekDate"
|
||||
>
|
||||
<CalendarCellTrigger
|
||||
:day="weekDate"
|
||||
:month="month.value"
|
||||
/>
|
||||
</CalendarCell>
|
||||
</CalendarGridRow>
|
||||
</CalendarGridBody>
|
||||
</CalendarGrid>
|
||||
</div>
|
||||
</CalendarRoot>
|
||||
</template>
|
||||
21
frontend/components/ui/calendar/CalendarCell.vue
Normal file
21
frontend/components/ui/calendar/CalendarCell.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarCell, type CalendarCellProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarCellProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarCell
|
||||
:class="cn('relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:rounded-md [&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-view])]:bg-accent/50', props.class)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot />
|
||||
</CalendarCell>
|
||||
</template>
|
||||
35
frontend/components/ui/calendar/CalendarCellTrigger.vue
Normal file
35
frontend/components/ui/calendar/CalendarCellTrigger.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarCellTrigger, type CalendarCellTriggerProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
|
||||
const props = defineProps<CalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarCellTrigger
|
||||
:class="cn(
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'h-9 w-9 p-0 font-normal',
|
||||
'[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',
|
||||
// Selected
|
||||
'data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[selected]:opacity-100 data-[selected]:hover:bg-primary data-[selected]:hover:text-primary-foreground data-[selected]:focus:bg-primary data-[selected]:focus:text-primary-foreground',
|
||||
// Disabled
|
||||
'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',
|
||||
// Unavailable
|
||||
'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',
|
||||
// Outside months
|
||||
'data-[outside-view]:text-muted-foreground data-[outside-view]:opacity-50 [&[data-outside-view][data-selected]]:bg-accent/50 [&[data-outside-view][data-selected]]:text-muted-foreground [&[data-outside-view][data-selected]]:opacity-30',
|
||||
props.class,
|
||||
)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot />
|
||||
</CalendarCellTrigger>
|
||||
</template>
|
||||
21
frontend/components/ui/calendar/CalendarGrid.vue
Normal file
21
frontend/components/ui/calendar/CalendarGrid.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarGrid, type CalendarGridProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarGridProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarGrid
|
||||
:class="cn('w-full border-collapse space-y-1', props.class)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot />
|
||||
</CalendarGrid>
|
||||
</template>
|
||||
11
frontend/components/ui/calendar/CalendarGridBody.vue
Normal file
11
frontend/components/ui/calendar/CalendarGridBody.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { CalendarGridBody, type CalendarGridBodyProps } from 'reka-ui'
|
||||
|
||||
const props = defineProps<CalendarGridBodyProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarGridBody v-bind="props">
|
||||
<slot />
|
||||
</CalendarGridBody>
|
||||
</template>
|
||||
11
frontend/components/ui/calendar/CalendarGridHead.vue
Normal file
11
frontend/components/ui/calendar/CalendarGridHead.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { CalendarGridHead, type CalendarGridHeadProps } from 'reka-ui'
|
||||
|
||||
const props = defineProps<CalendarGridHeadProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarGridHead v-bind="props">
|
||||
<slot />
|
||||
</CalendarGridHead>
|
||||
</template>
|
||||
18
frontend/components/ui/calendar/CalendarGridRow.vue
Normal file
18
frontend/components/ui/calendar/CalendarGridRow.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarGridRow, type CalendarGridRowProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarGridRowProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarGridRow :class="cn('flex', props.class)" v-bind="forwardedProps">
|
||||
<slot />
|
||||
</CalendarGridRow>
|
||||
</template>
|
||||
18
frontend/components/ui/calendar/CalendarHeadCell.vue
Normal file
18
frontend/components/ui/calendar/CalendarHeadCell.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarHeadCell, type CalendarHeadCellProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarHeadCell :class="cn('w-9 rounded-md text-[0.8rem] font-normal text-muted-foreground', props.class)" v-bind="forwardedProps">
|
||||
<slot />
|
||||
</CalendarHeadCell>
|
||||
</template>
|
||||
18
frontend/components/ui/calendar/CalendarHeader.vue
Normal file
18
frontend/components/ui/calendar/CalendarHeader.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarHeader, type CalendarHeaderProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarHeaderProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarHeader :class="cn('relative flex w-full items-center justify-between pt-1', props.class)" v-bind="forwardedProps">
|
||||
<slot />
|
||||
</CalendarHeader>
|
||||
</template>
|
||||
28
frontend/components/ui/calendar/CalendarHeading.vue
Normal file
28
frontend/components/ui/calendar/CalendarHeading.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { CalendarHeading, type CalendarHeadingProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CalendarHeadingProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
defineSlots<{
|
||||
default: (props: { headingValue: string }) => any
|
||||
}>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarHeading
|
||||
v-slot="{ headingValue }"
|
||||
:class="cn('text-sm font-medium', props.class)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot :heading-value>
|
||||
{{ headingValue }}
|
||||
</slot>
|
||||
</CalendarHeading>
|
||||
</template>
|
||||
29
frontend/components/ui/calendar/CalendarNextButton.vue
Normal file
29
frontend/components/ui/calendar/CalendarNextButton.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronRight } from 'lucide-vue-next'
|
||||
import { CalendarNext, type CalendarNextProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
|
||||
const props = defineProps<CalendarNextProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarNext
|
||||
:class="cn(
|
||||
buttonVariants({ variant: 'outline' }),
|
||||
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
||||
props.class,
|
||||
)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</slot>
|
||||
</CalendarNext>
|
||||
</template>
|
||||
29
frontend/components/ui/calendar/CalendarPrevButton.vue
Normal file
29
frontend/components/ui/calendar/CalendarPrevButton.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronLeft } from 'lucide-vue-next'
|
||||
import { CalendarPrev, type CalendarPrevProps, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
|
||||
const props = defineProps<CalendarPrevProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarPrev
|
||||
:class="cn(
|
||||
buttonVariants({ variant: 'outline' }),
|
||||
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
||||
props.class,
|
||||
)"
|
||||
v-bind="forwardedProps"
|
||||
>
|
||||
<slot>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
</slot>
|
||||
</CalendarPrev>
|
||||
</template>
|
||||
12
frontend/components/ui/calendar/index.ts
Normal file
12
frontend/components/ui/calendar/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export { default as Calendar } from './Calendar.vue'
|
||||
export { default as CalendarCell } from './CalendarCell.vue'
|
||||
export { default as CalendarCellTrigger } from './CalendarCellTrigger.vue'
|
||||
export { default as CalendarGrid } from './CalendarGrid.vue'
|
||||
export { default as CalendarGridBody } from './CalendarGridBody.vue'
|
||||
export { default as CalendarGridHead } from './CalendarGridHead.vue'
|
||||
export { default as CalendarGridRow } from './CalendarGridRow.vue'
|
||||
export { default as CalendarHeadCell } from './CalendarHeadCell.vue'
|
||||
export { default as CalendarHeader } from './CalendarHeader.vue'
|
||||
export { default as CalendarHeading } from './CalendarHeading.vue'
|
||||
export { default as CalendarNextButton } from './CalendarNextButton.vue'
|
||||
export { default as CalendarPrevButton } from './CalendarPrevButton.vue'
|
||||
@@ -23,6 +23,7 @@
|
||||
<AppLogo />
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<!-- <AppOrgSelector v-model:model-value="selectedOrg" /> -->
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
@@ -84,7 +85,20 @@
|
||||
<span>{{ $t("menu.scanner") }}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
:class="{
|
||||
'text-nowrap': typeof locale === 'string' && locale.startsWith('zh-'),
|
||||
}"
|
||||
:tooltip="$t('menu.scanner')"
|
||||
@click.prevent="openDialog('scanner')"
|
||||
>
|
||||
<MdiAccount />
|
||||
<span>Collection Settings</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
|
||||
@@ -111,18 +125,29 @@
|
||||
<SidebarTrigger class="absolute left-2 top-2 hidden lg:flex" variant="default" />
|
||||
</div>
|
||||
<div
|
||||
class="sticky top-0 z-20 flex h-28 translate-y-[-0.5px] flex-col bg-secondary p-2 shadow-md sm:h-16 sm:flex-row"
|
||||
class="sticky top-0 z-20 flex h-28 translate-y-[-0.5px] flex-col bg-secondary p-2 shadow-md sm:h-16 sm:flex-row justify-between"
|
||||
:class="{
|
||||
'lg:hidden': preferences.displayLegacyHeader,
|
||||
}"
|
||||
>
|
||||
<div class="flex h-1/2 items-center gap-2 sm:h-auto">
|
||||
<div>
|
||||
<SidebarTrigger variant="default" />
|
||||
</div>
|
||||
<!-- <div>
|
||||
<Button size="icon">
|
||||
<AppLogo class="size-8" />
|
||||
</Button>
|
||||
</div> -->
|
||||
<NuxtLink to="/home">
|
||||
<AppHeaderText class="h-6" />
|
||||
</NuxtLink>
|
||||
<!-- <AppOrgSelector v-model:model-value="selectedOrg" /> -->
|
||||
|
||||
</div>
|
||||
<div class="sm:grow"></div>
|
||||
<!-- <div class="flex items-center">
|
||||
<AppOrgSelector v-model:model-value="selectedOrg" />
|
||||
</div> -->
|
||||
<div class="flex h-1/2 grow items-center justify-end gap-2 sm:h-auto">
|
||||
<Input
|
||||
v-model:model-value="search"
|
||||
@@ -209,6 +234,8 @@
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { toast } from "@/components/ui/sonner";
|
||||
|
||||
const selectedOrg = ref<any>();
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const username = computed(() => authCtx.user?.name || "User");
|
||||
|
||||
@@ -314,13 +341,13 @@
|
||||
name: computed(() => t("menu.maintenance")),
|
||||
to: "/maintenance",
|
||||
},
|
||||
{
|
||||
icon: MdiAccount,
|
||||
id: 5,
|
||||
active: computed(() => route.path === "/profile"),
|
||||
name: computed(() => t("menu.profile")),
|
||||
to: "/profile",
|
||||
},
|
||||
// {
|
||||
// icon: MdiAccount,
|
||||
// id: 5,
|
||||
// active: computed(() => route.path === "/profile"),
|
||||
// name: computed(() => t("menu.profile")),
|
||||
// to: "/profile",
|
||||
// },
|
||||
{
|
||||
icon: MdiCog,
|
||||
id: 6,
|
||||
@@ -368,6 +395,36 @@
|
||||
const authCtx = useAuthContext();
|
||||
const api = useUserApi();
|
||||
|
||||
const checkAuth = async () => {
|
||||
try {
|
||||
// await api.user.self();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
// if (!authCtx.isAuthorized()) {
|
||||
// console.log("Not authorised, redirecting to login");
|
||||
// await navigateTo("/");
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
checkAuth();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
const handleVisibilityChange = () => {
|
||||
if (!document.hidden) {
|
||||
checkAuth();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||
});
|
||||
});
|
||||
|
||||
async function logout() {
|
||||
await authCtx.logout(api);
|
||||
navigateTo("/");
|
||||
|
||||
362
frontend/pages/collection.vue
Normal file
362
frontend/pages/collection.vue
Normal file
@@ -0,0 +1,362 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { v4 as uuidv4 } from 'uuid'; // For generating unique invite IDs
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Card } from '@/components/ui/card'; // Assuming you have a Card component
|
||||
import { Badge } from '@/components/ui/badge'; // Assuming you have a Badge component
|
||||
import {
|
||||
Calendar as CalendarIcon,
|
||||
PlusCircle,
|
||||
Trash,
|
||||
} from 'lucide-vue-next'; // Icons
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
definePageMeta({
|
||||
middleware: ['auth'],
|
||||
});
|
||||
useHead({
|
||||
title: 'HomeBox | ' + t('menu.maintenance'),
|
||||
});
|
||||
|
||||
interface User {
|
||||
username: string;
|
||||
id: string;
|
||||
role: 'owner' | 'admin' | 'editor' | 'viewer';
|
||||
lastActive: string;
|
||||
added: string;
|
||||
}
|
||||
|
||||
interface Invite {
|
||||
id: string;
|
||||
code: string;
|
||||
expiresAt: Date | null;
|
||||
maxUses: number | null;
|
||||
uses: number;
|
||||
}
|
||||
|
||||
const users = ref<User[]>([
|
||||
{
|
||||
username: 'tonya',
|
||||
id: '1',
|
||||
role: 'owner',
|
||||
lastActive: '12 hours ago',
|
||||
added: '13 hours ago',
|
||||
},
|
||||
{
|
||||
username: 'steve',
|
||||
id: '2',
|
||||
role: 'admin',
|
||||
lastActive: '1 day ago',
|
||||
added: '2 days ago',
|
||||
},
|
||||
{
|
||||
username: 'bob',
|
||||
id: '3',
|
||||
role: 'editor',
|
||||
lastActive: '30 minutes ago',
|
||||
added: '5 hours ago',
|
||||
},
|
||||
{
|
||||
username: 'john',
|
||||
id: '4',
|
||||
role: 'viewer',
|
||||
lastActive: '2 hours ago',
|
||||
added: '1 day ago',
|
||||
},
|
||||
]);
|
||||
|
||||
const invites = ref<Invite[]>([
|
||||
{
|
||||
id: uuidv4(),
|
||||
code: 'ABCDEF',
|
||||
expiresAt: null,
|
||||
maxUses: null,
|
||||
uses: 0,
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
code: 'GHIJKL',
|
||||
expiresAt: new Date(new Date().setDate(new Date().getDate() + 7)), // Expires in 7 days
|
||||
maxUses: 5,
|
||||
uses: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
const newInviteExpiresAt = ref<Date | null>(null);
|
||||
const newInviteMaxUses = ref<number | null>(null);
|
||||
|
||||
const page = ref(1);
|
||||
|
||||
const roles = ['owner', 'admin', 'editor', 'viewer'];
|
||||
|
||||
function handleRoleChange(userId: string, newRole: string) {
|
||||
const userIndex = users.value.findIndex((user) => user.id === userId);
|
||||
if (userIndex !== -1) {
|
||||
users.value[userIndex].role = newRole as
|
||||
| 'owner'
|
||||
| 'admin'
|
||||
| 'editor'
|
||||
| 'viewer';
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemoveUser(userId: string) {
|
||||
users.value = users.value.filter((user) => user.id !== userId);
|
||||
}
|
||||
|
||||
function generateInviteCode() {
|
||||
return Math.random().toString(36).substring(2, 8).toUpperCase();
|
||||
}
|
||||
|
||||
function createNewInvite() {
|
||||
const newInvite: Invite = {
|
||||
id: uuidv4(),
|
||||
code: generateInviteCode(),
|
||||
expiresAt: newInviteExpiresAt.value,
|
||||
maxUses: newInviteMaxUses.value,
|
||||
uses: 0,
|
||||
};
|
||||
invites.value.push(newInvite);
|
||||
newInviteExpiresAt.value = null;
|
||||
newInviteMaxUses.value = null;
|
||||
}
|
||||
|
||||
function deleteInvite(inviteId: string) {
|
||||
invites.value = invites.value.filter((invite) => invite.id !== inviteId);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BaseContainer class="flex flex-col gap-4">
|
||||
<BaseSectionHeader> Collection Settings </BaseSectionHeader>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="page == 1 ? 'default' : 'outline'"
|
||||
@click="page = 1"
|
||||
>
|
||||
Users
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="page == 2 ? 'default' : 'outline'"
|
||||
@click="page = 2"
|
||||
>
|
||||
Invites
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="page == 3 ? 'default' : 'outline'"
|
||||
@click="page = 3"
|
||||
>
|
||||
Settings
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Card v-if="page == 1" class="p-4 m-4">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Username</TableHead>
|
||||
<TableHead>Role</TableHead>
|
||||
<TableHead>Last Active</TableHead>
|
||||
<TableHead>Added</TableHead>
|
||||
<TableHead class="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow v-for="user in users" :key="user.id">
|
||||
<TableCell class="font-medium">
|
||||
{{ user.username }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge
|
||||
:variant="
|
||||
user.role === 'owner'
|
||||
? 'default'
|
||||
: user.role === 'admin'
|
||||
? 'secondary'
|
||||
: 'outline'
|
||||
"
|
||||
>
|
||||
{{ user.role }}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>{{ user.lastActive }}</TableCell>
|
||||
<TableCell>{{ user.added }}</TableCell>
|
||||
<TableCell class="text-right">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button size="sm" variant="outline"> Edit </Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-48">
|
||||
<div class="grid gap-4">
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-medium leading-none">Edit User</h4>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ user.username }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="role">Role</Label>
|
||||
<Select
|
||||
:model-value="user.role"
|
||||
@update:model-value="
|
||||
(newRole) => handleRoleChange(user.id, newRole)
|
||||
"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a role" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
:value="role"
|
||||
>
|
||||
{{ role }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
@click="handleRemoveUser(user.id)"
|
||||
>
|
||||
Remove User
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
|
||||
<Card v-if="page == 2" class="p-4 m-4">
|
||||
<div class="flex flex-col gap-4">
|
||||
<h3 class="text-lg font-semibold">Existing Invites</h3>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Code</TableHead>
|
||||
<TableHead>Expires</TableHead>
|
||||
<TableHead>Max Uses</TableHead>
|
||||
<TableHead>Uses</TableHead>
|
||||
<TableHead class="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow v-for="invite in invites" :key="invite.id">
|
||||
<TableCell class="font-medium">
|
||||
{{ invite.code }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{{
|
||||
invite.expiresAt
|
||||
? format(invite.expiresAt, 'PPP')
|
||||
: 'Never'
|
||||
}}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{{ invite.maxUses !== null ? invite.maxUses : 'Unlimited' }}
|
||||
</TableCell>
|
||||
<TableCell>{{ invite.uses }}</TableCell>
|
||||
<TableCell class="text-right">
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
@click="deleteInvite(invite.id)"
|
||||
>
|
||||
<Trash class="w-4 h-4" />
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<hr class="my-4" />
|
||||
|
||||
<h3 class="text-lg font-semibold">Create New Invite</h3>
|
||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
<div class="flex flex-col gap-2">
|
||||
<Label for="new-invite-max-uses">Max Uses (optional)</Label>
|
||||
<Input
|
||||
id="new-invite-max-uses"
|
||||
type="number"
|
||||
v-model.number="newInviteMaxUses"
|
||||
placeholder="Unlimited"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Label for="new-invite-expires-at">Expires At (optional)</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="w-full justify-start text-left font-normal"
|
||||
:class="
|
||||
!newInviteExpiresAt && 'text-muted-foreground'
|
||||
"
|
||||
>
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
{{
|
||||
newInviteExpiresAt
|
||||
? format(newInviteExpiresAt, 'PPP')
|
||||
: 'Pick a date'
|
||||
}}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<Calendar v-model:model-value="newInviteExpiresAt" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<div class="flex items-end">
|
||||
<Button @click="createNewInvite" class="w-full">
|
||||
<PlusCircle class="mr-2 w-4 h-4" /> Generate Invite
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card v-if="page == 3" class="p-4 m-4">
|
||||
<h3 class="text-lg font-semibold">Collection Settings</h3>
|
||||
<p class="text-muted-foreground">
|
||||
This is where you would configure general collection settings.
|
||||
</p>
|
||||
<!-- Add your settings forms/components here -->
|
||||
</Card>
|
||||
</BaseContainer>
|
||||
</div>
|
||||
</template>
|
||||
28
frontend/pnpm-lock.yaml
generated
28
frontend/pnpm-lock.yaml
generated
@@ -8551,12 +8551,12 @@ snapshots:
|
||||
|
||||
'@nuxtjs/eslint-config-typescript@12.1.0(eslint@8.57.1)(typescript@5.6.2)':
|
||||
dependencies:
|
||||
'@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
'@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.2)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-vue: 9.33.0(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
@@ -8564,11 +8564,11 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)':
|
||||
'@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)':
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.57.1)
|
||||
eslint-plugin-node: 11.1.0(eslint@8.57.1)
|
||||
eslint-plugin-promise: 6.6.0(eslint@8.57.1)
|
||||
@@ -10655,10 +10655,10 @@ snapshots:
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
|
||||
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.57.1)
|
||||
eslint-plugin-promise: 6.6.0(eslint@8.57.1)
|
||||
|
||||
@@ -10670,7 +10670,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||
eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.0
|
||||
@@ -10681,18 +10681,18 @@ snapshots:
|
||||
tinyglobby: 0.2.12
|
||||
unrs-resolver: 1.5.0
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.2)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -10708,7 +10708,7 @@ snapshots:
|
||||
eslint-utils: 2.1.0
|
||||
regexpp: 3.2.0
|
||||
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1):
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.8
|
||||
@@ -10719,7 +10719,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
|
||||
Reference in New Issue
Block a user