use prop function createTag instead of event to make sure it is handled by the parent

This commit is contained in:
Gregor Vostrak
2024-07-15 18:19:04 +02:00
parent 655723db49
commit 1e4f0afa67
14 changed files with 60 additions and 71 deletions

View File

@@ -304,7 +304,7 @@ test('test that deleting a time entry from the overview works', async ({
await goToTimeOverview(page);
const timeEntryRows = page.locator('[data-testid="time_entry_row"]');
await createEmptyTimeEntry(page);
const timeEntryCount = await timeEntryRows.count();
await expect(timeEntryRows).toHaveCount(1);
const newTimeEntry = timeEntryRows.first();
const actionsDropdown = newTimeEntry
@@ -313,7 +313,7 @@ test('test that deleting a time entry from the overview works', async ({
await actionsDropdown.click();
const deleteButton = page.getByText('Delete');
await deleteButton.click();
await expect(timeEntryRows).toHaveCount(timeEntryCount - 1);
await expect(timeEntryRows).toHaveCount(0);
});
test.skip('test that load more works when the end of page is reached', async ({

View File

@@ -13,14 +13,15 @@ const tag = ref<CreateTagBody>({
name: '',
});
const emit = defineEmits<{
createTag: [name: string, callback: (tag: Tag) => void];
const props = defineProps<{
createTag: (name: string) => Promise<Tag | undefined>;
}>();
async function submit() {
emit('createTag', tag.value.name, () => {
const newTag = props.createTag(tag.value.name);
if (newTag !== undefined) {
show.value = false;
});
}
}
const tagNameInput = ref<HTMLInputElement | null>(null);

View File

@@ -8,6 +8,7 @@ import type { Tag } from '@/utils/api';
const props = defineProps<{
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const model = defineModel<string[]>({
@@ -66,14 +67,13 @@ const filteredTags = computed(() => {
});
});
function createTag(name: string, callback: (tag: Tag) => void) {
emit('createTag', name, (newTag: Tag) => {
if (newTag) {
addOrRemoveTagFromSelection(newTag.id);
}
searchValue.value = '';
callback(newTag);
});
async function createAndAddTag(name: string) {
const newTag = await props.createTag(name);
if (newTag) {
addOrRemoveTagFromSelection(newTag.id);
}
searchValue.value = '';
return newTag;
}
async function addTagIfNoneExists() {
@@ -109,7 +109,6 @@ function updateSearchValue(event: Event) {
const emit = defineEmits<{
changed: [];
submit: [];
createTag: [name: string, callback: (tag: Tag) => void];
}>();
function toggleTag(newValue: string) {
@@ -160,7 +159,7 @@ const showCreateTagModal = ref(false);
<template>
<TagCreateModal
@createTag="createTag"
:createTag="createAndAddTag"
v-model:show="showCreateTagModal"></TagCreateModal>
<Dropdown
@submit="emit('submit')"

View File

@@ -9,13 +9,18 @@ import TagTableRow from '@/Components/Common/Tag/TagTableRow.vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import TagTableHeading from '@/Components/Common/Tag/TagTableHeading.vue';
import { canCreateTags } from '@/utils/permissions';
import type { Tag } from '@/utils/api';
defineProps<{
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const { tags } = storeToRefs(useTagsStore());
const createTag = ref(false);
const showCreateTagModal = ref(false);
</script>
<template>
<TagCreateModal v-model:show="createTag"></TagCreateModal>
<TagCreateModal
:createTag
v-model:show="showCreateTagModal"></TagCreateModal>
<div class="flow-root">
<div class="inline-block min-w-full align-middle">
<div
@@ -34,7 +39,7 @@ const createTag = ref(false);
</p>
<SecondaryButton
v-if="canCreateTags()"
@click="createTag = true"
@click="showCreateTagModal = true"
:icon="PlusIcon"
>Create your First Tag</SecondaryButton
>

View File

@@ -21,13 +21,13 @@ const props = defineProps<{
projects: Project[];
tasks: Task[];
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const emit = defineEmits<{
onStartStopClick: [timeEntry: TimeEntry];
updateTimeEntries: [timeEntries: TimeEntry[]];
deleteTimeEntries: [timeEntries: TimeEntry[]];
createTag: [name: string, callback: (tag: Tag) => void];
}>();
function updateTimeEntryDescription(description: string) {
@@ -95,7 +95,7 @@ const expanded = ref(false);
</div>
<div class="flex items-center font-medium lg:space-x-2">
<TimeEntryRowTagDropdown
@createTag="(...args) => emit('createTag', ...args)"
:createTag
:tags="tags"
@changed="updateTimeEntryTags"
:modelValue="timeEntry.tags"></TimeEntryRowTagDropdown>
@@ -142,7 +142,7 @@ const expanded = ref(false);
@updateTimeEntry="(arg) => emit('updateTimeEntries', [arg])"
@onStartStopClick="emit('onStartStopClick', subEntry)"
@deleteTimeEntry="emit('deleteTimeEntries', [subEntry])"
@createTag="(...args) => emit('createTag', ...args)"
:createTag
:key="subEntry.id"
v-for="subEntry in timeEntry.timeEntries"
:time-entry="subEntry"></TimeEntryRow>

View File

@@ -17,7 +17,6 @@ import { storeToRefs } from 'pinia';
import { useTasksStore } from '@/utils/useTasks';
import { useProjectsStore } from '@/utils/useProjects';
import { useTagsStore } from '@/utils/useTags';
import type { Tag } from '@/utils/api';
const projectStore = useProjectsStore();
const { projects } = storeToRefs(projectStore);
const taskStore = useTasksStore();
@@ -75,11 +74,8 @@ async function submit() {
show.value = false;
}
const { tags } = storeToRefs(useTagsStore());
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
async function createTag(tag: string) {
return await useTagsStore().createTag(tag);
}
</script>
@@ -118,7 +114,7 @@ async function createTag(tag: string, callback: (tag: Tag) => void) {
<div class="flex items-center space-x-2 px-4">
<TimeTrackerTagDropdown
:tags="tags"
@createTag="createTag"
:createTag="createTag"
v-model="timeEntry.tags"></TimeTrackerTagDropdown>
<BillableToggleButton
v-model="timeEntry.billable"></BillableToggleButton>

View File

@@ -19,6 +19,7 @@ const props = defineProps<{
projects: Project[];
tasks: Task[];
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const emit = defineEmits<{
@@ -26,7 +27,6 @@ const emit = defineEmits<{
updateTimeEntries: [entries: TimeEntry[]];
deleteTimeEntries: [entries: TimeEntry[]];
createTimeEntry: [entry: Omit<CreateTimeEntryBody, 'member_id'>];
createTag: [name: string, callback: (tag: Tag) => void];
}>();
const groupedTimeEntries = computed(() => {
@@ -118,14 +118,14 @@ function startTimeEntryFromExisting(entry: TimeEntry) {
@onStartStopClick="startTimeEntryFromExisting(entry)"
@updateTimeEntries="(arg) => emit('updateTimeEntries', arg)"
@deleteTimeEntries="(arg) => emit('deleteTimeEntries', arg)"
@createTag="(...args) => emit('createTag', ...args)"
:createTag
v-if="'timeEntries' in entry && entry.timeEntries.length > 1"
:time-entry="entry"></TimeEntryAggregateRow>
<TimeEntryRow
:projects="projects"
:tasks="tasks"
:tags="tags"
@createTag="(...args) => emit('createTag', ...args)"
:createTag
@updateTimeEntry="(arg) => emit('updateTimeEntry', arg)"
@onStartStopClick="startTimeEntryFromExisting(entry)"
@deleteTimeEntry="() => emit('deleteTimeEntries', [entry])"

View File

@@ -16,13 +16,13 @@ const props = defineProps<{
projects: Project[];
tasks: Task[];
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const emit = defineEmits<{
onStartStopClick: [];
deleteTimeEntry: [];
updateTimeEntry: [timeEntry: TimeEntry];
createTag: [name: string, callback: (tag: Tag) => void];
}>();
function updateTimeEntryDescription(description: string) {
@@ -81,7 +81,7 @@ function updateProjectAndTask(projectId: string, taskId: string) {
<div class="flex items-center font-medium lg:space-x-2">
<TimeEntryRowTagDropdown
@changed="updateTimeEntryTags"
@createTag="(...args) => emit('createTag', ...args)"
:createTag
:tags="tags"
:modelValue="timeEntry.tags"></TimeEntryRowTagDropdown>
<BillableToggleButton

View File

@@ -6,10 +6,10 @@ import type { Tag } from '@/utils/api';
const props = defineProps<{
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const emit = defineEmits<{
createTag: [name: string, callback: (tag: Tag) => void];
changed: [model: string[]];
}>();
@@ -24,7 +24,7 @@ const timeEntryTags = computed<Tag[]>(() => {
<template>
<TagDropdown
:tags="tags"
@createTag="(...args) => emit('createTag', ...args)"
:createTag
@changed="emit('changed', model)"
v-model="model">
<template #trigger>

View File

@@ -7,7 +7,6 @@ import type { Tag } from '@/utils/api';
const emit = defineEmits<{
changed: [];
createTag: [name: string, callback: (tag: Tag) => void];
}>();
const model = defineModel({
@@ -22,12 +21,13 @@ const iconColorClasses = computed(() => {
});
defineProps<{
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
</script>
<template>
<TagDropdown
@createTag="(...args) => $emit('createTag', ...args)"
:createTag
@changed="emit('changed')"
v-model="model"
:tags="tags">

View File

@@ -21,7 +21,6 @@ import TimeTrackerRangeSelector from '@/Components/Common/TimeTracker/TimeTracke
import { useProjectsStore } from '@/utils/useProjects';
import { useTasksStore } from '@/utils/useTasks';
import { useTagsStore } from '@/utils/useTags';
import type { Tag } from '@/utils/api';
const page = usePage<{
auth: {
@@ -105,11 +104,8 @@ function switchToTimeEntryOrganization() {
switchOrganization(currentTimeEntry.value.organization_id);
}
}
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
async function createTag(tag: string) {
return await useTagsStore().createTag(tag);
}
const { tags } = storeToRefs(useTagsStore());
@@ -160,7 +156,7 @@ const { tags } = storeToRefs(useTagsStore());
<div class="flex items-center space-x-2 px-4">
<TimeTrackerTagDropdown
@changed="updateTimeEntry"
@createTag="createTag"
:createTag
:tags="tags"
v-model="
currentTimeEntry.tags

View File

@@ -21,7 +21,7 @@ import {
import { type GroupingOption, useReportingStore } from '@/utils/useReporting';
import { storeToRefs } from 'pinia';
import TagDropdown from '@/Components/Common/Tag/TagDropdown.vue';
import type { AggregatedTimeEntriesQueryParams, Tag } from '@/utils/api';
import type { AggregatedTimeEntriesQueryParams } from '@/utils/api';
import ReportingFilterBadge from '@/Components/Common/Reporting/ReportingFilterBadge.vue';
import ProjectMultiselectDropdown from '@/Components/Common/Project/ProjectMultiselectDropdown.vue';
import MemberMultiselectDropdown from '@/Components/Common/Member/MemberMultiselectDropdown.vue';
@@ -139,11 +139,8 @@ onMounted(() => {
});
const { tags } = storeToRefs(useTagsStore());
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
async function createTag(tag: string) {
return await useTagsStore().createTag(tag);
}
</script>
@@ -205,7 +202,7 @@ async function createTag(tag: string, callback: (tag: Tag) => void) {
</ClientMultiselectDropdown>
<TagDropdown
@submit="updateReporting"
@createTag="createTag"
:createTag
v-model="selectedTags"
:tags="tags">
<template v-slot:trigger>

View File

@@ -9,13 +9,11 @@ import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import PageTitle from '@/Components/Common/PageTitle.vue';
import { canCreateTags } from '@/utils/permissions';
import { useTagsStore } from '@/utils/useTags';
import type { Tag } from '@/utils/api';
const showCreateTagModal = ref(false);
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
async function createTag(tag: string) {
return await useTagsStore().createTag(tag);
}
</script>
@@ -24,18 +22,18 @@ async function createTag(tag: string, callback: (tag: Tag) => void) {
<MainContainer
class="py-5 border-b border-default-background-separator flex justify-between items-center">
<div class="flex items-center space-x-6">
<PageTitle :icon="TagIcon" title="Tags"> </PageTitle>
<PageTitle :icon="TagIcon" title="Tags"></PageTitle>
</div>
<SecondaryButton
v-if="canCreateTags()"
:icon="PlusIcon"
@click="showCreateTagModal = true"
>Create Tag</SecondaryButton
>
>Create Tag
</SecondaryButton>
<TagCreateModal
@createTag="createTag"
:createTag="createTag"
v-model:show="showCreateTagModal"></TagCreateModal>
</MainContainer>
<TagTable></TagTable>
<TagTable :createTag="createTag"></TagTable>
</AppLayout>
</template>

View File

@@ -5,7 +5,7 @@ import { onMounted, ref, watch } from 'vue';
import MainContainer from '@/Pages/MainContainer.vue';
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
import { storeToRefs } from 'pinia';
import type { CreateTimeEntryBody, Tag, TimeEntry } from '@/utils/api';
import type { CreateTimeEntryBody, TimeEntry } from '@/utils/api';
import { useElementVisibility } from '@vueuse/core';
import { ClockIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
@@ -77,11 +77,8 @@ const { projects } = storeToRefs(projectStore);
const taskStore = useTasksStore();
const { tasks } = storeToRefs(taskStore);
async function createTag(name: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(name);
if (newTag !== undefined) {
callback(newTag);
}
async function createTag(name: string) {
return await useTagsStore().createTag(name);
}
</script>
@@ -111,7 +108,7 @@ async function createTag(name: string, callback: (tag: Tag) => void) {
@updateTimeEntries="updateTimeEntries"
@deleteTimeEntries="deleteTimeEntries"
@createTimeEntry="startTimeEntry"
@createTag="createTag"
:createTag
:projects="projects"
:tasks="tasks"
:timeEntries="timeEntries"