Skip to content

Commit c8cad3d

Browse files
committed
sync
1 parent 4d55bfe commit c8cad3d

File tree

9 files changed

+187
-79
lines changed

9 files changed

+187
-79
lines changed

packages/cubejs-playground/src/QueryBuilderV2/QueryBuilderExtras.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const LIMIT_OPTIONS: { key: number; label: string }[] = [
5353
{ key: 1000, label: '1,000' },
5454
{ key: 5000, label: '5,000 (Default)' },
5555
{ key: 50000, label: '50,000 (Max)' },
56-
];
56+
] as const;
5757
const LIMIT_OPTION_VALUES = LIMIT_OPTIONS.map((option) => option.key) as number[];
5858

5959
function timezoneByName(name: string) {

packages/cubejs-playground/src/QueryBuilderV2/components/ChartRenderer.tsx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
} from '@cubejs-client/core';
88
import { UseCubeQueryResult } from '@cubejs-client/react';
99
import { Skeleton, Tag, tasty } from '@cube-dev/ui-kit';
10-
import formatDate from 'date-fns/format';
1110
import { ComponentType, memo, useCallback, useMemo } from 'react';
1211
import { Col, Row, Statistic, Table } from 'antd';
1312
import {
@@ -34,28 +33,10 @@ import {
3433
getChartColorByIndex,
3534
getChartSolidColorByIndex,
3635
} from '../utils/chart-colors';
36+
import { formatDateByGranularity, formatDateByPattern } from '../utils/index';
3737

3838
import { LocalError } from './LocalError';
3939

40-
const FORMAT_MAP = {
41-
second: 'HH:mm:ss, yyyy-LL-dd',
42-
minute: 'HH:mm, yyyy-LL-dd',
43-
hour: 'HH:00, yyyy-LL-dd',
44-
day: 'yyyy-LL-dd',
45-
week: "'W'w yyyy-LL-dd",
46-
month: 'LLL yyyy',
47-
quarter: 'QQQ yyyy',
48-
year: 'yyyy',
49-
};
50-
51-
export function formatDateByGranularity(timestamp: Date, granularity?: TimeDimensionGranularity) {
52-
return formatDate(timestamp, FORMAT_MAP[granularity ?? 'second']);
53-
}
54-
55-
export function formatDateByPattern(timestamp: Date, format?: string) {
56-
return formatDate(timestamp, format ?? FORMAT_MAP['second']);
57-
}
58-
5940
function CustomDot(props: any) {
6041
const { cx, cy, fill } = props;
6142

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { CalendarEditIcon, CalendarIcon, Text, TooltipProvider } from '@cube-dev/ui-kit';
2+
import { useRef } from 'react';
3+
4+
import { useHasOverflow } from '../hooks/index';
5+
import { titleize } from '../utils/index';
6+
7+
import { ListMemberButton } from './ListMemberButton';
8+
9+
export interface GranularityListMemberProps {
10+
name: string;
11+
title?: string;
12+
isCustom?: boolean;
13+
isSelected: boolean;
14+
onToggle: () => void;
15+
}
16+
17+
export function GranularityListMember(props: GranularityListMemberProps) {
18+
const { name, title, isCustom, isSelected, onToggle } = props;
19+
const textRef = useRef<HTMLDivElement>(null);
20+
21+
const hasOverflow = useHasOverflow(textRef);
22+
const isAutoTitle = titleize(name) === title;
23+
24+
const button = (
25+
<ListMemberButton
26+
icon={isCustom ? <CalendarEditIcon /> : <CalendarIcon />}
27+
data-member="timeDimension"
28+
isSelected={isSelected}
29+
onPress={onToggle}
30+
>
31+
<Text ref={textRef} ellipsis>
32+
{name}
33+
</Text>
34+
</ListMemberButton>
35+
);
36+
37+
if (hasOverflow || (!isAutoTitle && isCustom)) {
38+
return (
39+
<TooltipProvider
40+
title={
41+
<>
42+
<Text preset="t4">{name}</Text>
43+
<br />
44+
<Text preset="t3">{title}</Text>
45+
</>
46+
}
47+
delay={1000}
48+
placement="right"
49+
>
50+
{button}
51+
</TooltipProvider>
52+
);
53+
} else {
54+
return button;
55+
}
56+
}

packages/cubejs-playground/src/QueryBuilderV2/components/ListMember.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { TCubeMeasure, TCubeDimension, TCubeSegment, Cube, MemberType } from '@cubejs-client/core';
1212
import { PlusOutlined } from '@ant-design/icons';
1313

14-
import { getTypeIcon } from '../utils';
14+
import { getTypeIcon, titleize } from '../utils';
1515
import { PrimaryKeyIcon } from '../icons/PrimaryKeyIcon';
1616
import { NonPublicIcon } from '../icons/NonPublicIcon';
1717
import { ItemInfoIcon } from '../icons/ItemInfoIcon';
@@ -60,6 +60,8 @@ export function ListMember(props: ListMemberProps) {
6060
const description = member.description;
6161

6262
const hasOverflow = useHasOverflow(textRef);
63+
const isAutoTitle = titleize(member.name) === title;
64+
6365
const button = (
6466
<ListMemberWrapper>
6567
<ListMemberButton
@@ -122,11 +124,15 @@ export function ListMember(props: ListMemberProps) {
122124
</ListMemberWrapper>
123125
);
124126

125-
return hasOverflow ? (
127+
return hasOverflow || !isAutoTitle ? (
126128
<TooltipProvider
127129
title={
128130
<>
129-
<b>{name}</b>
131+
<Text preset="t4">
132+
<b>{name}</b>
133+
</Text>
134+
<br />
135+
<Text preset="t4">{title}</Text>
130136
</>
131137
}
132138
delay={1000}

packages/cubejs-playground/src/QueryBuilderV2/components/SidePanelCubeItem.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ArrowIcon } from '../icons/ArrowIcon';
1616
import { NonPublicIcon } from '../icons/NonPublicIcon';
1717
import { ItemInfoIcon } from '../icons/ItemInfoIcon';
1818
import { useHasOverflow, useFilteredMembers } from '../hooks';
19+
import { titleize } from '../utils/index';
1920

2021
import { ListMember } from './ListMember';
2122
import { TimeListMember } from './TimeListMember';
@@ -366,6 +367,7 @@ export function SidePanelCubeItem({
366367
}, [segments.join(','), query?.segments?.join(','), showMembers, mode, meta]);
367368

368369
const hasOverflow = useHasOverflow(textRef);
370+
const isAutoTitle = titleize(name) === title;
369371

370372
const noVisibleMembers = !dimensions.length && !measures.length && !segments.length;
371373

@@ -468,12 +470,16 @@ export function SidePanelCubeItem({
468470
return (
469471
<Space flow="column" gap="0">
470472
<CubeWrapper>
471-
{hasOverflow ? (
473+
{hasOverflow || !isAutoTitle ? (
472474
<TooltipProvider
473475
delay={1000}
474476
title={
475477
<>
476-
<b>{name}</b>
478+
<Text preset="t4">
479+
<b>{name}</b>
480+
</Text>
481+
<br />
482+
<Text preset="t4">{title}</Text>
477483
</>
478484
}
479485
placement="right"

packages/cubejs-playground/src/QueryBuilderV2/components/TimeListMember.tsx

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
1-
import { useRef, useState } from 'react';
2-
import {
3-
Action,
4-
Flex,
5-
Space,
6-
Text,
7-
TimeIcon,
8-
CalendarIcon,
9-
CalendarEditIcon,
10-
TooltipProvider,
11-
} from '@cube-dev/ui-kit';
1+
import { useMemo, useRef, useState } from 'react';
2+
import { Flex, Space, Text, TimeIcon, TooltipProvider } from '@cube-dev/ui-kit';
123
import { Cube, TCubeDimension, TimeDimensionGranularity } from '@cubejs-client/core';
134

5+
import { GranularityListMember } from '@/modules/playground/components/QueryBuilder/components/GranularityListMember';
6+
147
import { ArrowIcon } from '../icons/ArrowIcon';
158
import { NonPublicIcon } from '../icons/NonPublicIcon';
169
import { ItemInfoIcon } from '../icons/ItemInfoIcon';
1710
import { useHasOverflow } from '../hooks/has-overflow';
11+
import { titleize } from '../utils/index';
1812

1913
import { ListMemberButton } from './ListMemberButton';
2014
import { FilterByMemberButton } from './FilterByMemberButton';
21-
import { MemberBadge } from './Badge';
2215
import { FilteredLabel } from './FilteredLabel';
2316

2417
interface ListMemberProps {
@@ -70,8 +63,21 @@ export function TimeListMember(props: ListMemberProps) {
7063

7164
const customGranularities =
7265
member.type === 'time' && member.granularities ? member.granularities.map((g) => g.name) : [];
66+
const customGranularitiesTitleMap = useMemo(() => {
67+
return (
68+
member.type === 'time' &&
69+
member.granularities?.reduce(
70+
(map, granularity) => {
71+
map[granularity.name] = granularity.title;
72+
73+
return map;
74+
},
75+
{} as Record<string, string>
76+
)
77+
);
78+
}, [member.type === 'time' ? member.granularities : null]);
7379
const memberGranularities = customGranularities.concat(PREDEFINED_GRANULARITIES);
74-
const isGranularitySelectedMap = {};
80+
const isGranularitySelectedMap: Record<string, boolean> = {};
7581
memberGranularities.forEach((granularity) => {
7682
isGranularitySelectedMap[granularity] = isSelected(granularity);
7783
});
@@ -80,6 +86,8 @@ export function TimeListMember(props: ListMemberProps) {
8086
open = isCompact ? false : open;
8187

8288
const hasOverflow = useHasOverflow(textRef);
89+
const isAutoTitle = titleize(member.name) === title;
90+
8391
const button = (
8492
<ListMemberButton
8593
icon={
@@ -106,22 +114,7 @@ export function TimeListMember(props: ListMemberProps) {
106114
<Text ref={textRef} ellipsis>
107115
{filterString ? <FilteredLabel text={name} filter={filterString} /> : name}
108116
</Text>
109-
{(isCompact || !open) && selectedGranularity ? (
110-
<TooltipProvider
111-
delay={1000}
112-
title="Click the granularity label to remove it from the query"
113-
>
114-
<Action
115-
onPress={() => {
116-
onGranularityToggle(member.name, selectedGranularity);
117-
}}
118-
>
119-
<MemberBadge isSpecial type="timeDimension">
120-
{selectedGranularity}
121-
</MemberBadge>
122-
</Action>
123-
</TooltipProvider>
124-
) : null}
117+
125118
<Space gap=".5x">
126119
<Space gap="1x">
127120
{description ? <ItemInfoIcon title={title} description={description} /> : undefined}
@@ -137,30 +130,34 @@ export function TimeListMember(props: ListMemberProps) {
137130
</ListMemberButton>
138131
);
139132

140-
const granularityItems = (items, icon) => {
141-
if (!open || isCompact) {
142-
return null;
143-
}
144-
145-
return items.map((granularity, i) => (
146-
<ListMemberButton
147-
key={`${name}.${granularity}`}
148-
icon={icon}
149-
data-member="timeDimension"
150-
isSelected={isGranularitySelectedMap[granularity]}
151-
onPress={() => {
152-
onGranularityToggle(member.name, granularity);
153-
setOpen(false);
154-
}}
155-
>
156-
<Text ellipsis>{granularity}</Text>
157-
</ListMemberButton>
158-
));
133+
const granularityItems = (items: string[], isCustom?: boolean) => {
134+
return items.map((granularity: string) => {
135+
if (
136+
((!open || isCompact) && !isGranularitySelectedMap[granularity]) ||
137+
!customGranularitiesTitleMap
138+
) {
139+
return null;
140+
}
141+
142+
return (
143+
<GranularityListMember
144+
key={`${name}.${granularity}`}
145+
name={granularity}
146+
title={customGranularitiesTitleMap[granularity]}
147+
isCustom={isCustom}
148+
isSelected={isGranularitySelectedMap[granularity]}
149+
onToggle={() => {
150+
onGranularityToggle(member.name, granularity);
151+
setOpen(false);
152+
}}
153+
/>
154+
);
155+
});
159156
};
160157

161158
return (
162159
<>
163-
{hasOverflow ? (
160+
{hasOverflow || !isAutoTitle ? (
164161
<TooltipProvider
165162
title={
166163
<>
@@ -175,7 +172,7 @@ export function TimeListMember(props: ListMemberProps) {
175172
) : (
176173
button
177174
)}
178-
{open || isCompact ? (
175+
{open || isCompact || selectedGranularity ? (
179176
<Flex flow="column" gap="1bw" padding="4.5x left">
180177
{open && !isCompact ? (
181178
<ListMemberButton
@@ -190,8 +187,8 @@ export function TimeListMember(props: ListMemberProps) {
190187
<Text ellipsis>value</Text>
191188
</ListMemberButton>
192189
) : null}
193-
{granularityItems(customGranularities, <CalendarEditIcon />)}
194-
{granularityItems(PREDEFINED_GRANULARITIES, <CalendarIcon />)}
190+
{granularityItems(customGranularities, true)}
191+
{granularityItems(PREDEFINED_GRANULARITIES)}
195192
</Flex>
196193
) : null}
197194
</>

packages/cubejs-playground/src/QueryBuilderV2/utils/format-date-by-granularity.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ const FORMAT_MAP = {
1313
};
1414

1515
export function formatDateByGranularity(timestamp: Date, granularity?: TimeDimensionGranularity) {
16-
return formatDate(timestamp, FORMAT_MAP[granularity ?? 'second']);
16+
return formatDate(
17+
timestamp,
18+
FORMAT_MAP[(granularity as Exclude<TimeDimensionGranularity, string>) ?? 'second'] ??
19+
FORMAT_MAP['second']
20+
);
1721
}
1822

1923
export function formatDateByPattern(timestamp: Date, format?: string) {

packages/cubejs-playground/src/QueryBuilderV2/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export * from './use-commit-press';
1111
export * from './uncapitalize';
1212
export * from './uniq-array';
1313
export * from './graphql-converters';
14+
export * from './titleize';

0 commit comments

Comments
 (0)