mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-13 10:42:16 +01:00
upgrade inertia v2; add prefetching; migrate queries to tanstack query
vue
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import MultiselectDropdown from '@/packages/ui/src/Input/MultiselectDropdown.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import type { Client } from '@/packages/api/src';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { useClientsQuery } from '@/utils/useClientsQuery';
|
||||
|
||||
const clientsStore = useClientsStore();
|
||||
const { clients } = storeToRefs(clientsStore);
|
||||
const { clients } = useClientsQuery();
|
||||
|
||||
function getKeyFromItem(item: Client) {
|
||||
return item.id;
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { useMembersQuery } from '@/utils/useMembersQuery';
|
||||
import { UserIcon, ChevronDownIcon } from '@heroicons/vue/24/solid';
|
||||
import { useFocus } from '@vueuse/core';
|
||||
import type { ProjectMember } from '@/packages/api/src';
|
||||
import { Badge, SelectDropdown } from '@/packages/ui/src';
|
||||
import type { Member } from '@/packages/api/src';
|
||||
|
||||
const membersStore = useMembersStore();
|
||||
const { members } = storeToRefs(membersStore);
|
||||
const { members } = useMembersQuery();
|
||||
|
||||
const model = defineModel<string>({
|
||||
default: '',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { Member } from '@/packages/api/src';
|
||||
import { api } from '@/packages/api/src';
|
||||
import { useForm } from '@tanstack/vue-form';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query';
|
||||
import Modal from '@/packages/ui/src/Modal.vue';
|
||||
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
|
||||
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
|
||||
@@ -11,7 +11,6 @@ import { useNotificationsStore } from '@/utils/notification';
|
||||
import { getCurrentOrganizationId } from '@/utils/useUser';
|
||||
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
|
||||
import InputError from '@/packages/ui/src/Input/InputError.vue';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean;
|
||||
@@ -23,6 +22,7 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { handleApiRequestNotifications } = useNotificationsStore();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
@@ -43,7 +43,7 @@ const deleteMutation = useMutation({
|
||||
},
|
||||
onSuccess: () => {
|
||||
close();
|
||||
useMembersStore().fetchMembers();
|
||||
queryClient.invalidateQueries({ queryKey: ['members'] });
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ import DialogModal from '@/packages/ui/src/DialogModal.vue';
|
||||
import { ref } from 'vue';
|
||||
import { api, type Member } from '@/packages/api/src';
|
||||
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query';
|
||||
import { getCurrentOrganizationId } from '@/utils/useUser';
|
||||
import { useNotificationsStore } from '@/utils/notification';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
|
||||
const { handleApiRequestNotifications } = useNotificationsStore();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = ref(false);
|
||||
@@ -41,7 +41,7 @@ async function submit() {
|
||||
'There was an error deactivating the user.',
|
||||
() => {
|
||||
show.value = false;
|
||||
useMembersStore().fetchMembers();
|
||||
queryClient.invalidateQueries({ queryKey: ['members'] });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import MultiselectDropdown from '@/packages/ui/src/Input/MultiselectDropdown.vue';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useMembersQuery } from '@/utils/useMembersQuery';
|
||||
import type { Member } from '@/packages/api/src';
|
||||
|
||||
const membersStore = useMembersStore();
|
||||
const { members } = storeToRefs(membersStore);
|
||||
const { members } = useMembersQuery();
|
||||
|
||||
function getKeyFromItem(item: Member) {
|
||||
return item.id;
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import MemberTableHeading from '@/Components/Common/Member/MemberTableHeading.vue';
|
||||
import MemberTableRow from '@/Components/Common/Member/MemberTableRow.vue';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { useMembersQuery } from '@/utils/useMembersQuery';
|
||||
|
||||
const { members } = storeToRefs(useMembersStore());
|
||||
|
||||
onMounted(async () => {
|
||||
await useMembersStore().fetchMembers();
|
||||
});
|
||||
const { members } = useMembersQuery();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -15,14 +15,12 @@ import MemberMakePlaceholderModal from '@/Components/Common/Member/MemberMakePla
|
||||
import MemberDeleteModal from '@/Components/Common/Member/MemberDeleteModal.vue';
|
||||
import { capitalizeFirstLetter } from '../../../utils/format';
|
||||
import { formatCents } from '../../../packages/ui/src/utils/money';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
|
||||
const props = defineProps<{
|
||||
member: Member;
|
||||
}>();
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
const memberStore = useMembersStore();
|
||||
|
||||
const showEditMemberModal = ref(false);
|
||||
const showMergeMemberModal = ref(false);
|
||||
@@ -31,7 +29,6 @@ const showDeleteMemberModal = ref(false);
|
||||
|
||||
function removeMember() {
|
||||
showDeleteMemberModal.value = true;
|
||||
memberStore.fetchMembers();
|
||||
}
|
||||
|
||||
async function invitePlaceholder(id: string) {
|
||||
|
||||
@@ -10,7 +10,7 @@ defineProps<{
|
||||
<template>
|
||||
<h3
|
||||
class="text-text-primary font-semibold text-sm sm:text-base flex items-center space-x-2 sm:space-x-2.5">
|
||||
<component :is="icon" class="w-5 sm:w-6 text-icon-default"></component>
|
||||
<component :is="icon" class="w-5 text-icon-default"></component>
|
||||
<span> {{ title }} </span>
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
@@ -6,11 +6,11 @@ import { computed, ref } from 'vue';
|
||||
import type { CreateClientBody, CreateProjectBody, Project } from '@/packages/api/src';
|
||||
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { useFocus } from '@vueuse/core';
|
||||
import ClientDropdown from '@/packages/ui/src/Client/ClientDropdown.vue';
|
||||
import Badge from '@/packages/ui/src/Badge.vue';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useClientsQuery } from '@/utils/useClientsQuery';
|
||||
import ProjectColorSelector from '@/packages/ui/src/Project/ProjectColorSelector.vue';
|
||||
import { UserCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import EstimatedTimeSection from '@/packages/ui/src/EstimatedTimeSection.vue';
|
||||
@@ -21,7 +21,7 @@ import ProjectEditBillableSection from '@/packages/ui/src/Project/ProjectEditBil
|
||||
import { isAllowedToPerformPremiumAction } from '@/utils/billing';
|
||||
|
||||
const { updateProject } = useProjectsStore();
|
||||
const { clients } = storeToRefs(useClientsStore());
|
||||
const { clients } = useClientsQuery();
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = ref(false);
|
||||
const showBillableRateModal = ref(false);
|
||||
|
||||
@@ -13,7 +13,7 @@ import { canCreateProjects } from '@/utils/permissions';
|
||||
import type { CreateProjectBody, Project, Client, CreateClientBody } from '@/packages/api/src';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useClientsQuery } from '@/utils/useClientsQuery';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import { isAllowedToPerformPremiumAction } from '@/utils/billing';
|
||||
import {
|
||||
@@ -34,7 +34,7 @@ const emit = defineEmits<{
|
||||
sort: [column: SortColumn];
|
||||
}>();
|
||||
|
||||
const { clients } = storeToRefs(useClientsStore());
|
||||
const { clients } = useClientsQuery();
|
||||
|
||||
// Create a map of client names for sorting
|
||||
const clientNameMap = computed(() => {
|
||||
|
||||
@@ -3,9 +3,8 @@ import ProjectMoreOptionsDropdown from '@/Components/Common/Project/ProjectMoreO
|
||||
import type { Project } from '@/packages/api/src';
|
||||
import { computed, ref, inject, type ComputedRef } from 'vue';
|
||||
import { CheckCircleIcon, ArchiveBoxIcon } from '@heroicons/vue/24/outline';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useClientsQuery } from '@/utils/useClientsQuery';
|
||||
import { useTasksQuery } from '@/utils/useTasksQuery';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import TableRow from '@/Components/TableRow.vue';
|
||||
import ProjectEditModal from '@/Components/Common/Project/ProjectEditModal.vue';
|
||||
@@ -17,8 +16,8 @@ import { formatHumanReadableDuration } from '../../../packages/ui/src/utils/time
|
||||
import { isAllowedToPerformPremiumAction } from '@/utils/billing';
|
||||
import type { Organization } from '@/packages/api/src';
|
||||
|
||||
const { clients } = storeToRefs(useClientsStore());
|
||||
const { tasks } = storeToRefs(useTasksStore());
|
||||
const { clients } = useClientsQuery();
|
||||
const { tasks } = useTasksQuery();
|
||||
|
||||
const props = defineProps<{
|
||||
project: Project;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { TrashIcon, PencilSquareIcon } from '@heroicons/vue/20/solid';
|
||||
import type { ProjectMember } from '@/packages/api/src';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useMembersQuery } from '@/utils/useMembersQuery';
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -19,7 +18,7 @@ const props = defineProps<{
|
||||
projectMember: ProjectMember;
|
||||
}>();
|
||||
|
||||
const { members } = storeToRefs(useMembersStore());
|
||||
const { members } = useMembersQuery();
|
||||
|
||||
const currentMember = computed(() => {
|
||||
return members.value.find((member) => member.id === props.projectMember.user_id);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { ProjectMember } from '@/packages/api/src';
|
||||
import { computed, ref, inject, type ComputedRef } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import TableRow from '@/Components/TableRow.vue';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { useMembersQuery } from '@/utils/useMembersQuery';
|
||||
import { useProjectMembersStore } from '@/utils/useProjectMembers';
|
||||
import ProjectMemberMoreOptionsDropdown from '@/Components/Common/ProjectMember/ProjectMemberMoreOptionsDropdown.vue';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
@@ -29,7 +28,7 @@ function editProjectMember() {
|
||||
showEditModal.value = true;
|
||||
}
|
||||
|
||||
const { members } = storeToRefs(useMembersStore());
|
||||
const { members } = useMembersQuery();
|
||||
const member = computed(() => {
|
||||
return members.value.find((member) => member.id === props.projectMember.member_id);
|
||||
});
|
||||
|
||||
@@ -39,12 +39,13 @@ import {
|
||||
type Organization,
|
||||
} from '@/packages/api/src';
|
||||
import { getCurrentMembershipId, getCurrentOrganizationId, getCurrentRole } from '@/utils/useUser';
|
||||
import { useTagsQuery } from '@/utils/useTagsQuery';
|
||||
import { useTagsStore } from '@/utils/useTags';
|
||||
import { useSessionStorage, useStorage } from '@vueuse/core';
|
||||
import { useNotificationsStore } from '@/utils/notification';
|
||||
import type { ExportFormat } from '@/types/reporting';
|
||||
import { getRandomColorWithSeed } from '@/packages/ui/src/utils/color';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useProjectsQuery } from '@/utils/useProjectsQuery';
|
||||
|
||||
// TimeEntryRoundingType is now defined in ReportingRoundingControls component
|
||||
type TimeEntryRoundingType = 'up' | 'down' | 'nearest';
|
||||
@@ -154,7 +155,7 @@ onMounted(() => {
|
||||
updateTableReporting();
|
||||
});
|
||||
|
||||
const { tags } = storeToRefs(useTagsStore());
|
||||
const { tags } = useTagsQuery();
|
||||
|
||||
async function createTag(tag: string) {
|
||||
return await useTagsStore().createTag(tag);
|
||||
@@ -199,8 +200,7 @@ async function downloadExport(format: ExportFormat) {
|
||||
|
||||
const { getNameForReportingRowEntry, emptyPlaceholder } = useReportingStore();
|
||||
|
||||
const projectsStore = useProjectsStore();
|
||||
const { projects } = storeToRefs(projectsStore);
|
||||
const { projects } = useProjectsQuery();
|
||||
const showExportModal = ref(false);
|
||||
const exportUrl = ref<string | null>(null);
|
||||
|
||||
@@ -375,7 +375,7 @@ const tableData = computed(() => {
|
||||
</MainContainer>
|
||||
<MainContainer>
|
||||
<div class="sm:grid grid-cols-4 pt-6 items-start">
|
||||
<div class="col-span-3 bg-card-background rounded-lg border border-card-border pt-3">
|
||||
<div class="col-span-3 bg-secondary rounded-lg border border-card-border pt-3">
|
||||
<div
|
||||
class="text-sm flex text-text-primary items-center space-x-3 font-medium px-6 border-b border-card-background-separator pb-3">
|
||||
<span>Group by</span>
|
||||
@@ -391,7 +391,7 @@ const tableData = computed(() => {
|
||||
</div>
|
||||
<div class="grid items-center" style="grid-template-columns: 1fr 100px 150px">
|
||||
<div
|
||||
class="contents [&>*]:border-card-background-separator [&>*]:border-b [&>*]:bg-tertiary [&>*]:pb-1.5 [&>*]:pt-1 text-text-secondary text-sm">
|
||||
class="contents [&>*]:border-card-background-separator [&>*]:border-b [&>*]:bg-secondary [&>*]:pb-1.5 [&>*]:pt-1 text-text-tertiary text-sm">
|
||||
<div class="pl-6">Name</div>
|
||||
<div class="text-right">Duration</div>
|
||||
<div class="text-right pr-6">Cost</div>
|
||||
|
||||
@@ -3,8 +3,7 @@ import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
|
||||
import { FolderPlusIcon } from '@heroicons/vue/24/solid';
|
||||
import { PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import { ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useTagsStore } from '@/utils/useTags';
|
||||
import { useTagsQuery } from '@/utils/useTagsQuery';
|
||||
import TagTableRow from '@/Components/Common/Tag/TagTableRow.vue';
|
||||
import TagCreateModal from '@/packages/ui/src/Tag/TagCreateModal.vue';
|
||||
import TagTableHeading from '@/Components/Common/Tag/TagTableHeading.vue';
|
||||
@@ -13,7 +12,7 @@ import type { Tag } from '@/packages/api/src';
|
||||
defineProps<{
|
||||
createTag: (name: string) => Promise<Tag | undefined>;
|
||||
}>();
|
||||
const { tags } = storeToRefs(useTagsStore());
|
||||
const { tags } = useTagsQuery();
|
||||
const showCreateTagModal = ref(false);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import MultiselectDropdown from '@/packages/ui/src/Input/MultiselectDropdown.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import type { Task } from '@/packages/api/src';
|
||||
import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useTasksQuery } from '@/utils/useTasksQuery';
|
||||
|
||||
const tasksStore = useTasksStore();
|
||||
const { tasks } = storeToRefs(tasksStore);
|
||||
const { tasks } = useTasksQuery();
|
||||
|
||||
function getKeyFromItem(item: Task) {
|
||||
return item.id;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import ProjectBadge from '@/packages/ui/src/Project/ProjectBadge.vue';
|
||||
import TimeTrackerStartStop from '@/packages/ui/src/TimeTrackerStartStop.vue';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useProjectsQuery } from '@/utils/useProjectsQuery';
|
||||
import { computed } from 'vue';
|
||||
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { getDayJsInstance } from '@/packages/ui/src/utils/time';
|
||||
import type { TimeEntry } from '@/packages/api/src';
|
||||
import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useTasksQuery } from '@/utils/useTasksQuery';
|
||||
import { ChevronRightIcon } from '@heroicons/vue/16/solid';
|
||||
|
||||
const props = defineProps<{
|
||||
timeEntry: TimeEntry;
|
||||
}>();
|
||||
|
||||
const { projects } = storeToRefs(useProjectsStore());
|
||||
const { projects } = useProjectsQuery();
|
||||
|
||||
const project = computed(() => {
|
||||
return projects.value.find((project) => project.id === props.timeEntry.project_id);
|
||||
});
|
||||
|
||||
const { tasks } = storeToRefs(useTasksStore());
|
||||
const { tasks } = useTasksQuery();
|
||||
|
||||
const task = computed(() => {
|
||||
return tasks.value.find((task) => task.id === props.timeEntry.task_id);
|
||||
|
||||
@@ -26,6 +26,7 @@ defineProps<{
|
||||
<Link
|
||||
v-else
|
||||
:href="href ?? ''"
|
||||
prefetch
|
||||
class="block px-4 py-2 text-sm leading-5 text-text-primary hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
|
||||
<slot />
|
||||
</Link>
|
||||
|
||||
@@ -15,7 +15,7 @@ const classes = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Link :href="href ?? ''" :class="classes">
|
||||
<Link :href="href ?? ''" :class="classes" prefetch>
|
||||
<slot />
|
||||
</Link>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,7 @@ defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Link :href="href" class="block group">
|
||||
<Link :href="href" class="block group" prefetch>
|
||||
<div
|
||||
:class="[
|
||||
current
|
||||
|
||||
@@ -21,7 +21,7 @@ const classes = computed(() => {
|
||||
<slot />
|
||||
</button>
|
||||
|
||||
<Link v-else :href="href ?? ''" :class="classes">
|
||||
<Link v-else :href="href ?? ''" :class="classes" prefetch>
|
||||
<slot />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,12 @@ import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { getCurrentOrganizationId } from '@/utils/useUser';
|
||||
import { switchOrganization } from '@/utils/useOrganization';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useProjectsQuery } from '@/utils/useProjectsQuery';
|
||||
import { useTasksQuery } from '@/utils/useTasksQuery';
|
||||
import { useTagsQuery } from '@/utils/useTagsQuery';
|
||||
import { useClientsQuery } from '@/utils/useClientsQuery';
|
||||
import { useTagsStore } from '@/utils/useTags';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import TimeTrackerControls from '@/packages/ui/src/TimeTracker/TimeTrackerControls.vue';
|
||||
import type {
|
||||
CreateClientBody,
|
||||
@@ -49,12 +52,9 @@ const currentTimeEntryStore = useCurrentTimeEntryStore();
|
||||
const { currentTimeEntry, isActive, now } = storeToRefs(currentTimeEntryStore);
|
||||
const { startLiveTimer, stopLiveTimer, setActiveState } = currentTimeEntryStore;
|
||||
|
||||
const projectStore = useProjectsStore();
|
||||
const { projects } = storeToRefs(projectStore);
|
||||
const taskStore = useTasksStore();
|
||||
const { tasks } = storeToRefs(taskStore);
|
||||
const clientStore = useClientsStore();
|
||||
const { clients } = storeToRefs(clientStore);
|
||||
const { projects } = useProjectsQuery();
|
||||
const { tasks } = useTasksQuery();
|
||||
const { clients } = useClientsQuery();
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [];
|
||||
@@ -157,7 +157,7 @@ async function discardCurrentTimeEntry() {
|
||||
}
|
||||
}
|
||||
|
||||
const { tags } = storeToRefs(useTagsStore());
|
||||
const { tags } = useTagsQuery();
|
||||
const { timeEntries } = storeToRefs(useTimeEntriesStore());
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user