mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
add client_ids to reporting filters
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Http\Requests\V1\TimeEntry;
|
||||
|
||||
use App\Enums\TimeEntryAggregationType;
|
||||
use App\Models\Client;
|
||||
use App\Models\Member;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
@@ -86,6 +87,19 @@ class TimeEntryAggregateRequest extends FormRequest
|
||||
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||
}),
|
||||
],
|
||||
// Filter by client IDs, client IDs are OR combined
|
||||
'client_ids' => [
|
||||
'array',
|
||||
'min:1',
|
||||
],
|
||||
'client_ids.*' => [
|
||||
'string',
|
||||
'uuid',
|
||||
new ExistsEloquent(Client::class, null, function (Builder $builder): Builder {
|
||||
/** @var Builder<Client> $builder */
|
||||
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||
}),
|
||||
],
|
||||
// Filter by tag IDs, tag IDs are AND combined
|
||||
'tag_ids' => [
|
||||
'array',
|
||||
|
||||
@@ -165,15 +165,16 @@ const v1_time_entries_update_multiple_Body = z
|
||||
.passthrough();
|
||||
const updateTimeEntry_Body = z
|
||||
.object({
|
||||
member_id: z.string().uuid().optional(),
|
||||
project_id: z.union([z.string(), z.null()]).optional(),
|
||||
task_id: z.union([z.string(), z.null()]).optional(),
|
||||
member_id: z.string().uuid(),
|
||||
project_id: z.union([z.string(), z.null()]),
|
||||
task_id: z.union([z.string(), z.null()]),
|
||||
start: z.string(),
|
||||
end: z.union([z.string(), z.null()]).optional(),
|
||||
billable: z.boolean().optional(),
|
||||
description: z.union([z.string(), z.null()]).optional(),
|
||||
tags: z.union([z.array(z.string()), z.null()]).optional(),
|
||||
end: z.union([z.string(), z.null()]),
|
||||
billable: z.boolean(),
|
||||
description: z.union([z.string(), z.null()]),
|
||||
tags: z.union([z.array(z.string()), z.null()]),
|
||||
})
|
||||
.partial()
|
||||
.passthrough();
|
||||
|
||||
export const schemas = {
|
||||
@@ -2114,6 +2115,11 @@ If the group parameters are all set to `null` or are all missing, the
|
||||
type: 'Query',
|
||||
schema: z.array(z.string()).min(1).optional(),
|
||||
},
|
||||
{
|
||||
name: 'client_ids',
|
||||
type: 'Query',
|
||||
schema: z.array(z.string()).min(1).optional(),
|
||||
},
|
||||
{
|
||||
name: 'tag_ids',
|
||||
type: 'Query',
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import MultiselectDropdown from '@/Components/Common/MultiselectDropdown.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import type { Client } from '@/utils/api';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
|
||||
const clientsStore = useClientsStore();
|
||||
const { clients } = storeToRefs(clientsStore);
|
||||
|
||||
function getKeyFromItem(item: Client) {
|
||||
return item.id;
|
||||
}
|
||||
|
||||
function getNameForItem(item: Client) {
|
||||
return item.name;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MultiselectDropdown
|
||||
searchPlaceholder="Search for a Client..."
|
||||
:items="clients"
|
||||
:get-key-from-item="getKeyFromItem"
|
||||
:get-name-for-item="getNameForItem">
|
||||
<template #trigger>
|
||||
<slot name="trigger"></slot>
|
||||
</template>
|
||||
</MultiselectDropdown>
|
||||
</template>
|
||||
@@ -28,6 +28,7 @@ import ReportingRow from '@/Components/Common/Reporting/ReportingRow.vue';
|
||||
import { formatCents } from '@/utils/money';
|
||||
import ReportingPieChart from '@/Components/Common/Reporting/ReportingPieChart.vue';
|
||||
import { getCurrentMembershipId, getCurrentRole } from '@/utils/useUser';
|
||||
import ClientMultiselectDropdown from '@/Components/Common/Client/ClientMultiselectDropdown.vue';
|
||||
|
||||
const startDate = ref<string | null>(
|
||||
getDayJsInstance()().subtract(14, 'd').format('YYYY-MM-DD')
|
||||
@@ -37,6 +38,8 @@ const selectedTags = ref<string[]>([]);
|
||||
const selectedProjects = ref<string[]>([]);
|
||||
const selectedMembers = ref<string[]>([]);
|
||||
const selectedTasks = ref<string[]>([]);
|
||||
const selectedClients = ref<string[]>([]);
|
||||
|
||||
const billable = ref<'true' | 'false' | null>(null);
|
||||
|
||||
type GroupingOption = 'project' | 'task' | 'user' | 'billable' | 'client';
|
||||
@@ -49,36 +52,25 @@ function getFilterAttributes() {
|
||||
start: getDayJsInstance()(startDate.value).utc().format(),
|
||||
end: getDayJsInstance()(endDate.value).endOf('day').utc().format(),
|
||||
};
|
||||
if (selectedMembers.value.length > 0) {
|
||||
params = {
|
||||
...params,
|
||||
member_ids: selectedMembers.value,
|
||||
};
|
||||
}
|
||||
if (selectedProjects.value.length > 0) {
|
||||
params = {
|
||||
...params,
|
||||
project_ids: selectedProjects.value,
|
||||
};
|
||||
}
|
||||
if (selectedTasks.value.length > 0) {
|
||||
params = {
|
||||
...params,
|
||||
task_ids: selectedTasks.value,
|
||||
};
|
||||
}
|
||||
if (selectedTags.value.length > 0) {
|
||||
params = {
|
||||
...params,
|
||||
tag_ids: selectedTags.value,
|
||||
};
|
||||
}
|
||||
if (billable.value !== null) {
|
||||
params = {
|
||||
...params,
|
||||
billable: billable.value,
|
||||
};
|
||||
}
|
||||
params = {
|
||||
...params,
|
||||
member_ids:
|
||||
selectedMembers.value.length > 0
|
||||
? selectedMembers.value
|
||||
: undefined,
|
||||
project_ids:
|
||||
selectedProjects.value.length > 0
|
||||
? selectedProjects.value
|
||||
: undefined,
|
||||
task_ids:
|
||||
selectedTasks.value.length > 0 ? selectedTasks.value : undefined,
|
||||
client_ids:
|
||||
selectedClients.value.length > 0
|
||||
? selectedClients.value
|
||||
: undefined,
|
||||
tag_ids: selectedTags.value.length > 0 ? selectedTags.value : undefined,
|
||||
billable: billable.value !== null ? billable.value : undefined,
|
||||
};
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -179,6 +171,15 @@ onMounted(() => {
|
||||
:icon="CheckCircleIcon"></ReportingFilterBadge>
|
||||
</template>
|
||||
</TaskMultiselectDropdown>
|
||||
<ClientMultiselectDropdown
|
||||
@submit="updateReporting"
|
||||
v-model="selectedClients">
|
||||
<template v-slot:trigger>
|
||||
<ReportingFilterBadge
|
||||
title="Clients"
|
||||
:icon="FolderIcon"></ReportingFilterBadge>
|
||||
</template>
|
||||
</ClientMultiselectDropdown>
|
||||
<TagDropdown
|
||||
@submit="updateReporting"
|
||||
v-model="selectedTags">
|
||||
|
||||
Reference in New Issue
Block a user