mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-12 02:02:15 +01:00
restrict group and subgroup so they are always different
This commit is contained in:
@@ -1,50 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { FolderIcon } from '@heroicons/vue/16/solid';
|
||||
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
|
||||
import Badge from '@/Components/Common/Badge.vue';
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
UserCircleIcon,
|
||||
UserGroupIcon,
|
||||
} from '@heroicons/vue/20/solid';
|
||||
import BillableIcon from '@/Components/Common/Icons/BillableIcon.vue';
|
||||
|
||||
const groupByOptions = [
|
||||
{
|
||||
label: 'Members',
|
||||
value: 'user',
|
||||
icon: UserGroupIcon,
|
||||
},
|
||||
{
|
||||
label: 'Projects',
|
||||
value: 'project',
|
||||
icon: FolderIcon,
|
||||
},
|
||||
{
|
||||
label: 'Tasks',
|
||||
value: 'task',
|
||||
icon: CheckCircleIcon,
|
||||
},
|
||||
{
|
||||
label: 'Clients',
|
||||
value: 'client',
|
||||
icon: UserCircleIcon,
|
||||
},
|
||||
{
|
||||
label: 'Billable',
|
||||
value: 'billable',
|
||||
icon: BillableIcon,
|
||||
},
|
||||
];
|
||||
import { type Component, computed } from 'vue';
|
||||
|
||||
const model = defineModel<string | null>({ default: null });
|
||||
|
||||
const props = defineProps<{
|
||||
groupByOptions: { value: string; label: string; icon: Component }[];
|
||||
}>();
|
||||
const icon = computed(() => {
|
||||
return groupByOptions.find((option) => option.value === model.value)?.icon;
|
||||
return props.groupByOptions.find((option) => option.value === model.value)
|
||||
?.icon;
|
||||
});
|
||||
const title = computed(() => {
|
||||
return groupByOptions.find((option) => option.value === model.value)?.label;
|
||||
return props.groupByOptions.find((option) => option.value === model.value)
|
||||
?.label;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import ReportingChart from '@/Components/Common/Reporting/ReportingChart.vue';
|
||||
import BillableIcon from '@/Components/Common/Icons/BillableIcon.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { formatHumanReadableDuration, getDayJsInstance } from '@/utils/time';
|
||||
import { useReportingStore } from '@/utils/useReporting';
|
||||
import { type GroupingOption, useReportingStore } from '@/utils/useReporting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import TagDropdown from '@/Components/Common/Tag/TagDropdown.vue';
|
||||
import type { AggregatedTimeEntriesQueryParams } from '@/utils/api';
|
||||
@@ -42,11 +42,16 @@ const selectedClients = ref<string[]>([]);
|
||||
|
||||
const billable = ref<'true' | 'false' | null>(null);
|
||||
|
||||
type GroupingOption = 'project' | 'task' | 'user' | 'billable' | 'client';
|
||||
|
||||
const group = ref<GroupingOption>('project');
|
||||
const subGroup = ref<GroupingOption>('task');
|
||||
|
||||
const reportingStore = useReportingStore();
|
||||
|
||||
const { aggregatedGraphTimeEntries, aggregatedTableTimeEntries } =
|
||||
storeToRefs(reportingStore);
|
||||
|
||||
const { groupByOptions } = reportingStore;
|
||||
|
||||
function getFilterAttributes() {
|
||||
let params: AggregatedTimeEntriesQueryParams = {
|
||||
start: getDayJsInstance()(startDate.value).utc().format(),
|
||||
@@ -90,6 +95,14 @@ function updateGraphReporting() {
|
||||
|
||||
function updateTableReporting() {
|
||||
const params = getFilterAttributes();
|
||||
if (group.value === subGroup.value) {
|
||||
const fallbackOption = groupByOptions.find(
|
||||
(el) => el.value !== group.value
|
||||
);
|
||||
if (fallbackOption?.value) {
|
||||
subGroup.value = fallbackOption.value;
|
||||
}
|
||||
}
|
||||
if (getCurrentRole() === 'employee') {
|
||||
params.member_id = getCurrentMembershipId();
|
||||
}
|
||||
@@ -103,11 +116,6 @@ function updateReporting() {
|
||||
updateTableReporting();
|
||||
}
|
||||
|
||||
const reportingStore = useReportingStore();
|
||||
|
||||
const { aggregatedGraphTimeEntries, aggregatedTableTimeEntries } =
|
||||
storeToRefs(reportingStore);
|
||||
|
||||
function getOptimalGroupingOption(diff: number): 'day' | 'week' | 'month' {
|
||||
if (diff <= 31) {
|
||||
return 'day';
|
||||
@@ -248,10 +256,16 @@ onMounted(() => {
|
||||
class="text-sm flex text-white items-center space-x-3 font-medium px-6 border-b border-card-background-separator pb-3">
|
||||
<span>Group by</span>
|
||||
<ReportingGroupBySelect
|
||||
:group-by-options="groupByOptions"
|
||||
@changed="updateTableReporting"
|
||||
v-model="group"></ReportingGroupBySelect>
|
||||
<span>and</span>
|
||||
<ReportingGroupBySelect
|
||||
:group-by-options="
|
||||
groupByOptions.filter(
|
||||
(el) => el.value !== group
|
||||
)
|
||||
"
|
||||
@changed="updateTableReporting"
|
||||
v-model="subGroup"></ReportingGroupBySelect>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore, storeToRefs } from 'pinia';
|
||||
import { api } from '../../../openapi.json.client';
|
||||
import { computed, ref } from 'vue';
|
||||
import { type Component, computed, ref } from 'vue';
|
||||
import type {
|
||||
AggregatedTimeEntries,
|
||||
AggregatedTimeEntriesQueryParams,
|
||||
@@ -12,6 +12,20 @@ import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
UserCircleIcon,
|
||||
UserGroupIcon,
|
||||
} from '@heroicons/vue/20/solid';
|
||||
import { FolderIcon } from '@heroicons/vue/16/solid';
|
||||
import BillableIcon from '@/Components/Common/Icons/BillableIcon.vue';
|
||||
|
||||
export type GroupingOption =
|
||||
| 'project'
|
||||
| 'task'
|
||||
| 'user'
|
||||
| 'billable'
|
||||
| 'client';
|
||||
|
||||
export const useReportingStore = defineStore('reporting', () => {
|
||||
const reportingGraphResponse = ref<ReportingResponse | null>(null);
|
||||
@@ -112,11 +126,44 @@ export const useReportingStore = defineStore('reporting', () => {
|
||||
return key;
|
||||
}
|
||||
|
||||
const groupByOptions: {
|
||||
label: string;
|
||||
value: GroupingOption;
|
||||
icon: Component;
|
||||
}[] = [
|
||||
{
|
||||
label: 'Members',
|
||||
value: 'user',
|
||||
icon: UserGroupIcon,
|
||||
},
|
||||
{
|
||||
label: 'Projects',
|
||||
value: 'project',
|
||||
icon: FolderIcon,
|
||||
},
|
||||
{
|
||||
label: 'Tasks',
|
||||
value: 'task',
|
||||
icon: CheckCircleIcon,
|
||||
},
|
||||
{
|
||||
label: 'Clients',
|
||||
value: 'client',
|
||||
icon: UserCircleIcon,
|
||||
},
|
||||
{
|
||||
label: 'Billable',
|
||||
value: 'billable',
|
||||
icon: BillableIcon,
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
aggregatedGraphTimeEntries,
|
||||
fetchGraphReporting,
|
||||
fetchTableReporting,
|
||||
aggregatedTableTimeEntries,
|
||||
getNameForReportingRowEntry,
|
||||
groupByOptions,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user