Skip to content

Commit 27e5b78

Browse files
authored
StatsHouse UI: update metric edit transport (#1982)
1 parent 3670f3f commit 27e5b78

File tree

14 files changed

+419
-289
lines changed

14 files changed

+419
-289
lines changed

statshouse-ui/src/admin/Admin.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,29 @@
66

77
import { FormPage } from './pages/FormPage';
88
import { CreatePage } from './pages/CreatePage';
9-
import { Route, Routes } from 'react-router-dom';
9+
import { Outlet, Route, Routes } from 'react-router-dom';
1010
import { AdminDashControl } from './AdminDashControl';
11+
import { MetricHistory } from '@/admin/pages/MetricHistory';
12+
import { MetricEditMenu } from '@/components2/MetricEdit/MetricEditMenu';
1113

1214
export function Admin(props: { yAxisSize: number; adminMode: boolean }) {
1315
const { yAxisSize, adminMode } = props;
1416

1517
return (
1618
<Routes>
1719
<Route path="create" element={<CreatePage yAxisSize={yAxisSize} />} />
18-
<Route path="edit/:metricName/*" element={<FormPage adminMode={adminMode} yAxisSize={yAxisSize} />} />
20+
<Route
21+
path="edit/:metricName"
22+
element={
23+
<div className="container-xl pt-3 pb-3">
24+
<MetricEditMenu />
25+
<Outlet />
26+
</div>
27+
}
28+
>
29+
<Route path="" element={<FormPage adminMode={adminMode} yAxisSize={yAxisSize} />} />
30+
<Route path="history" element={<MetricHistory adminMode={adminMode} />} />
31+
</Route>
1932
<Route path="dash/" element={<AdminDashControl />} />
2033
</Routes>
2134
);

statshouse-ui/src/admin/api/saveMetric.ts

Lines changed: 61 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,9 @@
55
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
66

77
import { isNotNil } from '@/common/helpers';
8-
import { IBackendKind, IBackendMetric, IKind, IMetric, ITag } from '../models/metric';
8+
import { IBackendKind, IKind, IMetric, ITag } from '../models/metric';
99
import { freeKeyPrefix } from '@/url2';
10-
11-
export function saveMetric(metric: IMetric) {
12-
const body: IBackendMetric = {
13-
description: metric.description,
14-
kind: (metric.kind + (metric.withPercentiles ? '_p' : '')) as IBackendKind,
15-
name: metric.name,
16-
metric_id: metric.id,
17-
string_top_name: metric.stringTopName,
18-
string_top_description: metric.stringTopDescription,
19-
weight: metric.weight,
20-
resolution: metric.resolution,
21-
visible: metric.visible,
22-
disable: metric.disable,
23-
tags: metric.tags.map((tag) => ({
24-
name: tag.name,
25-
description: tag.alias,
26-
raw: tag.raw_kind != null,
27-
raw_kind: tag.raw_kind,
28-
value_comments:
29-
tag.customMapping.length > 0
30-
? tag.customMapping.reduce(
31-
(acc, map) => {
32-
acc[map.from] = map.to;
33-
return acc;
34-
},
35-
{} as Record<string, string>
36-
)
37-
: undefined,
38-
})),
39-
tags_draft: Object.fromEntries(metric.tags_draft.map((t) => [t.name, t])),
40-
pre_key_tag_id: metric.pre_key_tag_id,
41-
pre_key_from: metric.pre_key_from ? metric.pre_key_from : 0,
42-
skip_max_host: !!metric.skip_max_host,
43-
skip_min_host: !!metric.skip_min_host,
44-
skip_sum_square: !!metric.skip_sum_square,
45-
pre_key_only: !!metric.pre_key_only,
46-
metric_type: metric.metric_type,
47-
version: metric.version,
48-
group_id: metric.group_id,
49-
fair_key_tag_ids: metric.fair_key_tag_ids,
50-
};
51-
52-
return fetch(`/api/metric${metric.id ? `?s=${metric.name}` : ''}`, {
53-
method: 'POST',
54-
body: JSON.stringify({ metric: body }),
55-
})
56-
.then((res) => res.json())
57-
.catch(() => {
58-
throw new Error('Unknown error');
59-
})
60-
.then((parsed) => {
61-
if ('error' in parsed) {
62-
throw new Error(parsed.error);
63-
}
64-
return parsed;
65-
});
66-
}
10+
import { ApiMetric, PostMetricMetaValue } from '@/api/metric';
6711

6812
export function resetMetricFlood(metricName: string) {
6913
return fetch(`/api/reset-flood?s=${metricName}`, {
@@ -81,19 +25,7 @@ export function resetMetricFlood(metricName: string) {
8125
});
8226
}
8327

84-
export const fetchMetric = async (url: string) => {
85-
const response = await fetch(url);
86-
if (!response.ok) {
87-
throw new Error(`Failed to fetch: ${url}`);
88-
}
89-
return response.json();
90-
};
91-
92-
export const fetchAndProcessMetric = async (url: string) => {
93-
const {
94-
data: { metric },
95-
} = await fetchMetric(url);
96-
28+
export function mapMetricToEdit({ data: { metric } }: ApiMetric): IMetric {
9729
const tags_draft: ITag[] = Object.entries(metric.tags_draft ?? {})
9830
.map(([, t]) => t as ITag)
9931
.filter(isNotNil);
@@ -102,7 +34,7 @@ export const fetchAndProcessMetric = async (url: string) => {
10234
return {
10335
id: metric.metric_id === undefined ? 0 : metric.metric_id,
10436
name: metric.name,
105-
description: metric.description,
37+
description: metric.description ?? '',
10638
kind: (metric.kind.endsWith('_p') ? metric.kind.replace('_p', '') : metric.kind) as IKind,
10739
stringTopName: metric.string_top_name === undefined ? '' : metric.string_top_name,
10840
stringTopDescription: metric.string_top_description === undefined ? '' : metric.string_top_description,
@@ -111,20 +43,21 @@ export const fetchAndProcessMetric = async (url: string) => {
11143
visible: metric.visible === undefined ? false : metric.visible,
11244
disable: metric.disable === undefined ? false : metric.disable,
11345
withPercentiles: metric.kind.endsWith('_p'),
114-
tags: metric.tags.map((tag: ITag, index: number) => ({
115-
name: tag.name === undefined || tag.name === `key${index}` ? '' : tag.name,
116-
alias: tag.description === undefined ? '' : tag.description,
117-
customMapping: tag.value_comments
118-
? Object.entries(tag.value_comments).map(([from, to]) => ({
119-
from,
120-
to,
121-
}))
122-
: [],
123-
isRaw: tag.raw || tag.raw_kind != null,
124-
raw_kind: tag.raw_kind,
125-
})),
46+
tags:
47+
metric.tags?.map((tag, index) => ({
48+
name: tag.name === undefined || tag.name === `key${index}` ? '' : tag.name,
49+
alias: tag.description === undefined ? '' : tag.description,
50+
customMapping: tag.value_comments
51+
? Object.entries(tag.value_comments).map(([from, to]) => ({
52+
from,
53+
to,
54+
}))
55+
: [],
56+
isRaw: tag.raw || tag.raw_kind != null,
57+
raw_kind: tag.raw_kind,
58+
})) ?? [],
12659
tags_draft,
127-
tagsSize: metric.tags.length,
60+
tagsSize: metric.tags?.length ?? 0,
12861
pre_key_tag_id: metric.pre_key_tag_id && freeKeyPrefix(metric.pre_key_tag_id),
12962
pre_key_from: metric.pre_key_from,
13063
metric_type: metric.metric_type,
@@ -135,4 +68,46 @@ export const fetchAndProcessMetric = async (url: string) => {
13568
skip_min_host: !!metric.skip_min_host,
13669
skip_sum_square: !!metric.skip_sum_square,
13770
};
138-
};
71+
}
72+
73+
export function mapEditToMetric(metric: IMetric): PostMetricMetaValue {
74+
return {
75+
description: metric.description,
76+
kind: (metric.kind + (metric.withPercentiles ? '_p' : '')) as IBackendKind,
77+
name: metric.name,
78+
metric_id: metric.id,
79+
string_top_name: metric.stringTopName,
80+
string_top_description: metric.stringTopDescription,
81+
weight: metric.weight,
82+
resolution: metric.resolution,
83+
visible: metric.visible,
84+
disable: metric.disable,
85+
tags: metric.tags.map((tag) => ({
86+
name: tag.name,
87+
description: tag.alias,
88+
raw: tag.raw_kind != null,
89+
raw_kind: tag.raw_kind,
90+
value_comments:
91+
tag.customMapping.length > 0
92+
? tag.customMapping.reduce(
93+
(acc, map) => {
94+
acc[map.from] = map.to;
95+
return acc;
96+
},
97+
{} as Record<string, string>
98+
)
99+
: undefined,
100+
})),
101+
tags_draft: Object.fromEntries(metric.tags_draft.map((t) => [t.name, t])),
102+
pre_key_tag_id: metric.pre_key_tag_id,
103+
pre_key_from: metric.pre_key_from ? metric.pre_key_from : 0,
104+
skip_max_host: !!metric.skip_max_host,
105+
skip_min_host: !!metric.skip_min_host,
106+
skip_sum_square: !!metric.skip_sum_square,
107+
pre_key_only: !!metric.pre_key_only,
108+
metric_type: metric.metric_type,
109+
version: metric.version,
110+
group_id: metric.group_id,
111+
fair_key_tag_ids: metric.fair_key_tag_ids,
112+
};
113+
}

statshouse-ui/src/admin/models/metric.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
// License, v. 2.0. If a copy of the MPL was not distributed with this
55
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
66

7-
import { RawValueKind } from '@/view/api';
8-
9-
export interface IShortMetric {
10-
readonly name: string;
11-
}
7+
import { MetricMetaTagRawKind } from '@/api/enum';
128

139
export interface ITag {
1410
readonly name: string;
@@ -17,7 +13,7 @@ export interface ITag {
1713
* @deprecated
1814
*/
1915
readonly raw?: boolean;
20-
readonly raw_kind?: RawValueKind;
16+
readonly raw_kind?: MetricMetaTagRawKind;
2117
readonly value_comments?: Readonly<Record<string, string>>;
2218
}
2319

@@ -28,11 +24,12 @@ export interface ITagAlias {
2824
readonly name: string;
2925
readonly alias: string;
3026
readonly isRaw?: boolean;
31-
readonly raw_kind?: RawValueKind;
27+
readonly raw_kind?: MetricMetaTagRawKind;
3228
readonly customMapping: { readonly from: string; readonly to: string }[];
3329
}
3430

35-
export interface IMetric extends IShortMetric {
31+
export interface IMetric {
32+
readonly name: string;
3633
readonly id: number;
3734
readonly description: string;
3835
readonly kind: IKind;
@@ -60,31 +57,3 @@ export interface IMetric extends IShortMetric {
6057
readonly group_id?: number;
6158
readonly fair_key_tag_ids?: string[];
6259
}
63-
64-
export interface IBackendMetric {
65-
readonly metric_id?: number;
66-
readonly name?: string;
67-
readonly description: string;
68-
readonly kind: IBackendKind;
69-
readonly tags: readonly ITag[];
70-
readonly tags_draft?: Partial<Record<string, ITag>>;
71-
readonly string_top_name?: string;
72-
readonly string_top_description?: string;
73-
readonly weight?: number;
74-
readonly resolution?: number;
75-
/**
76-
* @deprecated
77-
*/
78-
readonly visible?: boolean;
79-
readonly disable?: boolean;
80-
readonly pre_key_tag_id?: string;
81-
readonly pre_key_from?: number;
82-
readonly skip_max_host?: boolean;
83-
readonly skip_min_host?: boolean;
84-
readonly skip_sum_square?: boolean;
85-
readonly pre_key_only?: boolean;
86-
readonly metric_type?: string;
87-
readonly version?: number;
88-
readonly group_id?: number;
89-
readonly fair_key_tag_ids?: string[];
90-
}

statshouse-ui/src/admin/pages/CreatePage.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
import * as React from 'react';
88
import { Link, useNavigate } from 'react-router-dom';
99
import { IMetric } from '../models/metric';
10-
import { saveMetric } from '../api/saveMetric';
10+
import { mapEditToMetric } from '../api/saveMetric';
1111
import { maxTagsSize } from '@/common/settings';
1212
import { getDefaultTag } from '../storages/MetricFormValues/reducer';
1313
import { useMetricMeta } from '@/hooks/useMetricMeta';
14+
import { useMutationMetricMeta } from '@/api/metric';
1415

1516
export function CreatePage(props: { yAxisSize: number }) {
1617
const { yAxisSize } = props;
@@ -81,7 +82,8 @@ function useSubmitCreate(name: string) {
8182
const [isRunning, setRunning] = React.useState<boolean>(false);
8283
const [error, setError] = React.useState<string | null>(null);
8384
const [success, setSuccess] = React.useState<string | null>(null);
84-
85+
const mutationMetricMeta = useMutationMetricMeta();
86+
const createMetric = mutationMetricMeta.mutateAsync;
8587
const onSubmit = React.useCallback(() => {
8688
setError(null);
8789
setSuccess(null);
@@ -106,17 +108,22 @@ function useSubmitCreate(name: string) {
106108
tags_draft: [],
107109
tagsSize: maxTagsSize,
108110
};
109-
saveMetric(values)
110-
.then(() => {
111+
112+
createMetric(mapEditToMetric(values), {
113+
onSuccess: () => {
111114
setSuccess('Saved');
112115
setRunning(false);
113116
navigate(`/view?s=${name}`, { replace: true });
114-
})
115-
.catch((err) => {
116-
setError(err.message);
117+
},
118+
onError: (error) => {
119+
setError(error.message);
120+
setRunning(false);
121+
},
122+
onSettled: () => {
117123
setRunning(false);
118-
});
119-
}, [name, navigate]);
124+
},
125+
});
126+
}, [createMetric, name, navigate]);
120127

121128
return {
122129
isRunning,

0 commit comments

Comments
 (0)