mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
use prop function createTag instead of event to make sure it is handled by the parent
This commit is contained in:
@@ -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 ({
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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')"
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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])"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user