|
4 | 4 | import ClickableStringFilter from '$comp/filters/ClickableStringFilter.svelte';
|
5 | 5 | import DateTime from '$comp/formatters/DateTime.svelte';
|
6 | 6 | import Number from '$comp/formatters/Number.svelte';
|
| 7 | + import Percentage from '$comp/formatters/Percentage.svelte'; |
7 | 8 | import TimeAgo from '$comp/formatters/TimeAgo.svelte';
|
8 | 9 | import Muted from '$comp/typography/Muted.svelte';
|
9 | 10 | import { Badge } from '$comp/ui/badge';
|
10 | 11 | import { Button } from '$comp/ui/button';
|
11 | 12 | import * as Card from '$comp/ui/card';
|
12 | 13 | import * as Tooltip from '$comp/ui/tooltip';
|
| 14 | + import { getProjectCountQuery, getStackCountQuery } from '$features/events/api.svelte'; |
| 15 | + import { DEFAULT_OFFSET } from '$features/shared/api/api.svelte'; |
13 | 16 | import { getStackQuery } from '$features/stacks/api.svelte';
|
| 17 | + import { cardinality, max, min, sum } from '$shared/api/aggregations'; |
14 | 18 | import IconFirstOccurrence from '~icons/mdi/arrow-left-circle';
|
15 | 19 | import IconLastOccurrence from '~icons/mdi/arrow-right-circle';
|
16 | 20 | import IconCalendar from '~icons/mdi/calendar';
|
|
30 | 34 |
|
31 | 35 | let { changed, id }: Props = $props();
|
32 | 36 |
|
33 |
| - let stackResponse = getStackQuery({ |
| 37 | + const stackResponse = getStackQuery({ |
34 | 38 | route: {
|
35 | 39 | get id() {
|
36 | 40 | return id;
|
37 | 41 | }
|
38 | 42 | }
|
39 | 43 | });
|
40 | 44 |
|
| 45 | + const projectCountResponse = getProjectCountQuery({ |
| 46 | + params: { |
| 47 | + aggregations: 'cardinality:user' |
| 48 | + }, |
| 49 | + route: { |
| 50 | + get projectId() { |
| 51 | + return stackResponse.data?.project_id; |
| 52 | + } |
| 53 | + } |
| 54 | + }); |
| 55 | +
|
| 56 | + // TODO: Add stack charts for Occurrences, Average Value, Value Sum |
| 57 | + const stackCountResponse = getStackCountQuery({ |
| 58 | + params: { |
| 59 | + aggregations: `date:(date${DEFAULT_OFFSET ? '^' + DEFAULT_OFFSET : ''} cardinality:user sum:count~1) min:date max:date cardinality:user sum:count~1` |
| 60 | + }, |
| 61 | + route: { |
| 62 | + get stackId() { |
| 63 | + return id; |
| 64 | + } |
| 65 | + } |
| 66 | + }); |
| 67 | +
|
41 | 68 | const stack = $derived(stackResponse.data!);
|
| 69 | + const eventOccurrences = $derived(sum(stackCountResponse?.data?.aggregations, 'sum_count')?.value ?? 0); |
| 70 | + const totalOccurrences = $derived(stack && stack.total_occurrences > eventOccurrences ? stack.total_occurrences : eventOccurrences); |
| 71 | + const userCount = $derived(sum(stackCountResponse?.data?.aggregations, 'cardinality_user')?.value ?? 0); |
| 72 | + const totalUserCount = $derived(cardinality(projectCountResponse?.data?.aggregations, 'cardinality_user')?.value ?? 0); |
| 73 | + const firstOccurrence = $derived(min<string>(stackCountResponse?.data?.aggregations, 'min_date')?.value ?? stack?.first_occurrence); |
| 74 | + const lastOccurrence = $derived(max<string>(stackCountResponse?.data?.aggregations, 'max_date')?.value ?? stack?.last_occurrence); |
42 | 75 | </script>
|
43 | 76 |
|
44 | 77 | {#if stack}
|
|
62 | 95 | <Tooltip.Root>
|
63 | 96 | <Tooltip.Trigger class="flex flex-col items-center rounded-lg bg-muted p-2">
|
64 | 97 | <IconCalendar class="mb-1 size-6 text-primary" />
|
65 |
| - <span class="text-lg font-bold"><Number value={stack.total_occurrences} /></span> |
| 98 | + <span class="text-lg font-bold"><Number value={totalOccurrences} /></span> |
66 | 99 | <Muted>Total Events</Muted>
|
67 | 100 | </Tooltip.Trigger>
|
68 | 101 | <Tooltip.Content side="bottom">
|
69 |
| - <Number value={stack.total_occurrences} /> All Time |
| 102 | + <Number value={totalOccurrences} /> All Time |
70 | 103 | </Tooltip.Content>
|
71 | 104 | </Tooltip.Root>
|
72 | 105 | <Tooltip.Root>
|
73 | 106 | <Tooltip.Trigger class="flex flex-col items-center rounded-lg bg-muted p-2">
|
74 | 107 | <IconUsers class="mb-1 size-6 text-primary" />
|
75 |
| - <span class="text-lg font-bold"><Number value={12345} /></span> |
| 108 | + <span class="text-lg font-bold"><Percentage percent={(userCount / totalUserCount) * 100.0} /></span> |
76 | 109 | <Muted>Users Affected</Muted>
|
77 | 110 | </Tooltip.Trigger>
|
78 |
| - <Tooltip.Content side="bottom">Users Affected</Tooltip.Content> |
| 111 | + <Tooltip.Content side="bottom"><Number value={userCount} /> of <Number value={totalUserCount} /> Users Affected</Tooltip.Content> |
79 | 112 | </Tooltip.Root>
|
80 | 113 | <Tooltip.Root>
|
81 | 114 | <Tooltip.Trigger class="flex flex-col items-center rounded-lg bg-muted p-2">
|
82 | 115 | <IconFirstOccurrence class="mb-1 size-6 text-muted-foreground" />
|
83 |
| - <span class="text-lg font-bold"><TimeAgo value={stack.first_occurrence} /></span> |
| 116 | + <span class="text-lg font-bold"><TimeAgo value={firstOccurrence} /></span> |
84 | 117 | <Muted>First</Muted>
|
85 | 118 | </Tooltip.Trigger>
|
86 | 119 | <Tooltip.Content side="bottom">
|
|
90 | 123 | <Tooltip.Root>
|
91 | 124 | <Tooltip.Trigger class="flex flex-col items-center rounded-lg bg-muted p-2">
|
92 | 125 | <IconLastOccurrence class="mb-1 size-6 text-muted-foreground" />
|
93 |
| - <span class="text-lg font-bold"><TimeAgo value={stack.last_occurrence} /></span> |
| 126 | + <span class="text-lg font-bold"><TimeAgo value={lastOccurrence} /></span> |
94 | 127 | <Muted>Last</Muted>
|
95 | 128 | </Tooltip.Trigger>
|
96 | 129 | <Tooltip.Content side="bottom">
|
97 |
| - Last Occurred On <DateTime value={stack.last_occurrence} /> |
| 130 | + Last Occurred On <DateTime value={lastOccurrence} /> |
98 | 131 | </Tooltip.Content>
|
99 | 132 | </Tooltip.Root>
|
100 | 133 | </div>
|
|
0 commit comments