Skip to content

Commit

Permalink
Merge pull request #1575 from merico-dev/1565-basic-query-ui-for-meri…
Browse files Browse the repository at this point in the history
…co-metric-system-with-mock-data

1565 basic query UI for merico metric system with mock data
  • Loading branch information
GerilLeto authored Nov 19, 2024
2 parents 10e744f + 4a07eb5 commit cf83109
Show file tree
Hide file tree
Showing 75 changed files with 1,745 additions and 125 deletions.
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/api",
"version": "13.43.13",
"version": "13.44.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions api/src/api_models/dashboard_content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ export class Query {
})
id: string;

@IsIn(['postgresql', 'mysql', 'http', 'transform'])
@IsIn(['postgresql', 'mysql', 'http', 'transform', 'merico_metric_system'])
@ApiModelProperty({
description: 'Datasource type',
required: true,
})
type: 'postgresql' | 'mysql' | 'http' | 'transform';
type: 'postgresql' | 'mysql' | 'http' | 'transform' | 'merico_metric_system';

@IsString()
@ApiModelProperty({
Expand Down
8 changes: 4 additions & 4 deletions api/src/api_models/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class DataSource {
@ApiModelProperty({
description: 'type of the datasource',
required: true,
enum: ['postgresql', 'mysql', 'http', 'transform'],
enum: ['postgresql', 'mysql', 'http', 'transform', 'merico_metric_system'],
})
type: string;

Expand Down Expand Up @@ -232,13 +232,13 @@ export class DataSourcePaginationResponse implements PaginationResponse<DataSour
})
export class DataSourceCreateRequest {
@IsString()
@IsIn(['postgresql', 'mysql', 'http', 'transform'])
@IsIn(['postgresql', 'mysql', 'http', 'transform', 'merico_metric_system'])
@ApiModelProperty({
description: 'type of the datasource',
required: true,
enum: ['postgresql', 'mysql', 'http', 'transform'],
enum: ['postgresql', 'mysql', 'http', 'transform', 'merico_metric_system'],
})
type: 'postgresql' | 'mysql' | 'http' | 'transform';
type: 'postgresql' | 'mysql' | 'http' | 'transform' | 'merico_metric_system';

@IsString()
@Length(1, 250)
Expand Down
2 changes: 1 addition & 1 deletion api/src/controller/datasource.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export class DataSourceController implements interfaces.Controller {
}

private validateConfig(
type: 'mysql' | 'postgresql' | 'http' | 'transform',
type: 'mysql' | 'postgresql' | 'http' | 'transform' | 'merico_metric_system',
config: DataSourceConfig,
locale: string,
): void {
Expand Down
4 changes: 2 additions & 2 deletions api/src/services/datasource.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ export class DataSourceService {
}

async create(
type: 'mysql' | 'postgresql' | 'http' | 'transform',
type: 'mysql' | 'postgresql' | 'http' | 'transform' | 'merico_metric_system',
key: string,
config: DataSourceConfig,
locale: string,
): Promise<DataSource> {
if (type !== 'http' && type !== 'transform') {
if (type === 'mysql' || type === 'postgresql') {
await this.testDatabaseConfiguration(type, config, locale);
}
maybeEncryptPassword(config);
Expand Down
2 changes: 1 addition & 1 deletion api/tests/unit/validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,7 @@ describe('DataSourceCreateRequest', () => {
property: 'type',
children: [],
constraints: {
isIn: 'type must be one of the following values: postgresql, mysql, http, transform',
isIn: 'type must be one of the following values: postgresql, mysql, http, transform, merico_metric_system',
isString: 'type must be a string',
},
},
Expand Down
2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/dashboard",
"version": "13.43.13",
"version": "13.44.0",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/api-caller/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type TQueryPayload = {

export type TQueryStructureRequest = {
query_type: 'TABLES' | 'COLUMNS' | 'DATA' | 'INDEXES' | 'COUNT';
type: DataSourceType.Postgresql | DataSourceType.MySQL;
type: DataSourceType.Postgresql | DataSourceType.MySQL | DataSourceType.MericoMetricSystem;
key: string; // datasource key
table_schema: string;
table_name: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import { useTranslation } from 'react-i18next';
import { OnMount } from '@monaco-editor/react';
// @ts-expect-error type of this lib
import { constrainedEditor } from 'constrained-editor-plugin/dist/esm/constrainedEditor.js';
interface IInlineFunctionInput {
type Props = {
value: TFunctionString;
onChange: (v: TFunctionString) => void;
defaultValue: TFunctionString;
label: string;
restrictions?: MonacoEditorRestriction[];
}
};

export const InlineFunctionInput = forwardRef(
({ value, onChange, label, defaultValue, restrictions = [] }: IInlineFunctionInput, _ref: any) => {
export const InlineFunctionInput = forwardRef<HTMLElement, Props>(
({ value, onChange, label, defaultValue, restrictions = [] }, _ref) => {
const { t } = useTranslation();
const [localValue, setLocalValue] = useState<string>(value);

Expand Down
14 changes: 14 additions & 0 deletions dashboard/src/dashboard-editor/model/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ export const DashboardModel = types
content_id: self.content_id,
};
},
get queryVariables() {
const ret: Record<string, any> = {
context: {
...self.content.mock_context.current,
...self.context.current,
},
filters: self.content.filters.previewValues,
};

return ret;
},
get queryVariablesString() {
return JSON.stringify(this.queryVariables, null, 2);
},
}))
.actions((self) => ({
updateCurrentContent(content: DashboardContentDBType) {
Expand Down
3 changes: 1 addition & 2 deletions dashboard/src/dashboard-editor/model/datasources/tables.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getParent, types } from 'mobx-state-tree';
import { DataSourceType } from '~/model';
import { types } from 'mobx-state-tree';

export type TableInfoType = {
table_schema: string;
Expand Down
1 change: 1 addition & 0 deletions dashboard/src/dashboard-editor/model/filters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const FiltersModel = types
return self.current.map((f) => ({
label: f.label ?? f.key,
value: f.key,
widget: f.type,
}));
},
get sortedList() {
Expand Down
20 changes: 19 additions & 1 deletion dashboard/src/dashboard-editor/model/queries/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Instance, SnapshotIn } from 'mobx-state-tree';
import { QueryRenderModel } from '~/model';
import { QueryRenderModel, QueryUsageType } from '~/model';

export const QueryModel = QueryRenderModel.views((self) => ({
get canPreviewData() {
Expand All @@ -14,6 +14,24 @@ export const QueryModel = QueryRenderModel.views((self) => ({
}
return 'Need to pick a Data Source first';
},
get usage() {
return self.contentModel.findQueryUsage(self.id) as QueryUsageType[];
},
get runBySet() {
return new Set(...self.run_by);
},
keyInRunBy(key: string) {
return this.runBySet.has(key);
},
})).actions((self) => ({
changeRunByRecord(key: string, checked: boolean) {
const set = new Set(self.run_by);
if (!checked) {
set.delete(key);
} else {
set.add(key);
}
},
}));

export type QueryModelInstance = Instance<typeof QueryModel>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Text } from '@mantine/core';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useRenderContentModelContext } from '~/contexts';

interface IQueryStateMessage {
queryID: string;
}
export const QueryStateMessage = ({ queryID }: IQueryStateMessage) => {
export const QueryStateMessage = observer(({ queryID }: IQueryStateMessage) => {
const model = useRenderContentModelContext();
const { state, error } = model.getDataStuffByID(queryID);
const query = React.useMemo(() => model.queries.findByID(queryID), [model, queryID]);
Expand All @@ -28,4 +29,4 @@ export const QueryStateMessage = ({ queryID }: IQueryStateMessage) => {
}

return null;
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export const DBExplorerModal = observer(({ dataSource, triggerButtonProps = {} }
const { t } = useTranslation();
const [opened, setOpened] = useState(false);

if (dataSource.type === 'http') {
const { type } = dataSource;
if (type === 'http' || type === 'merico_metric_system') {
return null;
}
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { observer } from 'mobx-react-lite';
import { useEditContentModelContext } from '~/contexts';
import { QueryEditorForm } from './query-editor-form';
import { QueryModelInstance } from '~/dashboard-editor/model/queries';
import { MericoMetricQueryEditorForm } from './merico-metric-query-editor-form';

export const EditQuery = observer(({ id }: { id: string }) => {
const content = useEditContentModelContext();
Expand All @@ -20,5 +21,8 @@ export const EditQuery = observer(({ id }: { id: string }) => {
);
}

if (query.isMericoMetricQuery) {
return <MericoMetricQueryEditorForm queryModel={query} />;
}
return <QueryEditorForm queryModel={query} />;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Group, Stack, TextInput } from '@mantine/core';
import { observer } from 'mobx-react-lite';
import { useTranslation } from 'react-i18next';
import { QueryModelInstance } from '~/dashboard-editor/model';
import { SelectDataSource } from '../query-editor-form/select-data-source';
import { MoreActions } from './more-actions';
import { PreviewData } from './preview-data';
import { QueryTabs } from './query-tabs';
import { QueryVariablesPreview } from './query-variables-preview';
import { RunQuery } from './run-query';
import { SelectMetric } from './select-metric';

type Props = {
queryModel: QueryModelInstance;
};
export const MericoMetricQueryEditorForm = observer(({ queryModel }: Props) => {
const { t } = useTranslation();

return (
<Stack
pt={8}
pb={16}
px={24}
gap={8}
styles={{
root: {
height: '100vh',
overflow: 'hidden',
},
}}
>
<Group styles={{ root: { flexGrow: 0, flexShrink: 0 } }}>
<TextInput
size="xs"
placeholder={t('query.name_description')}
label={t('query.name')}
value={queryModel.name}
onChange={(e) => {
queryModel.setName(e.currentTarget.value);
}}
styles={{
root: {
flexGrow: 0,
width: 'calc(50% - 44px)',
},
}}
/>
</Group>
<Group justify="space-between" grow gap={8} align="flex-end" styles={{ root: { flexGrow: 0, flexShrink: 0 } }}>
<Group justify="flex-start" grow gap={24} align="flex-end">
<SelectDataSource queryModel={queryModel} size="xs" />
<SelectMetric queryModel={queryModel} />
</Group>
<Group justify="flex-end">
<RunQuery queryModel={queryModel} />
<MoreActions queryModel={queryModel} />
</Group>
</Group>

<Group
justify="space-between"
grow
gap={12}
align="flex-start"
sx={{ flexGrow: 0, flexShrink: 1, overflowY: 'hidden' }}
>
<QueryTabs queryModel={queryModel} />
<QueryVariablesPreview />
</Group>
<PreviewData queryModel={queryModel} />
</Stack>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { MericoIconProps } from './types';

export const MericoIconCopy = ({ width, height }: MericoIconProps) => (
<svg viewBox="0 0 16 16" fill="none" width={width} height={height}>
<g clipPath="url(#clip0_421_7552)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.33331 6.66634C6.96512 6.66634 6.66665 6.96482 6.66665 7.33301V13.333C6.66665 13.7012 6.96512 13.9997 7.33331 13.9997H13.3333C13.7015 13.9997 14 13.7012 14 13.333V7.33301C14 6.96482 13.7015 6.66634 13.3333 6.66634H7.33331ZM5.33331 7.33301C5.33331 6.22844 6.22874 5.33301 7.33331 5.33301H13.3333C14.4379 5.33301 15.3333 6.22844 15.3333 7.33301V13.333C15.3333 14.4376 14.4379 15.333 13.3333 15.333H7.33331C6.22874 15.333 5.33331 14.4376 5.33331 13.333V7.33301Z"
fill="#3D3E45"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.66669 2.00033C2.48988 2.00033 2.32031 2.07056 2.19528 2.19559C2.07026 2.32061 2.00002 2.49018 2.00002 2.66699V8.66699C2.00002 8.8438 2.07026 9.01337 2.19528 9.1384C2.32031 9.26342 2.48988 9.33366 2.66669 9.33366H3.33335C3.70154 9.33366 4.00002 9.63214 4.00002 10.0003C4.00002 10.3685 3.70154 10.667 3.33335 10.667H2.66669C2.13625 10.667 1.62755 10.4563 1.25247 10.0812C0.877401 9.70613 0.666687 9.19742 0.666687 8.66699V2.66699C0.666687 2.13656 0.877401 1.62785 1.25247 1.25278C1.62755 0.877706 2.13625 0.666992 2.66669 0.666992H8.66669C9.19712 0.666992 9.70583 0.877706 10.0809 1.25278C10.456 1.62785 10.6667 2.13656 10.6667 2.66699V3.33366C10.6667 3.70185 10.3682 4.00033 10 4.00033C9.63183 4.00033 9.33335 3.70185 9.33335 3.33366V2.66699C9.33335 2.49018 9.26312 2.32061 9.13809 2.19559C9.01307 2.07056 8.8435 2.00033 8.66669 2.00033H2.66669Z"
fill="#3D3E45"
/>
</g>
<defs>
<clipPath id="clip0_421_7552">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { MericoIconProps } from './types';

export const MericoIconDelete = ({ width, height, color = '#EB1212' }: MericoIconProps) => (
<svg viewBox="0 0 16 16" fill="none" width={width} height={height}>
<path
d="M6.66665 6.66699C7.03484 6.66699 7.33331 6.96547 7.33331 7.33366V11.3337C7.33331 11.7018 7.03484 12.0003 6.66665 12.0003C6.29846 12.0003 5.99998 11.7018 5.99998 11.3337V7.33366C5.99998 6.96547 6.29846 6.66699 6.66665 6.66699Z"
fill={color}
/>
<path
d="M9.99998 11.3337V7.33366C9.99998 6.96547 9.7015 6.66699 9.33331 6.66699C8.96512 6.66699 8.66665 6.96547 8.66665 7.33366V11.3337C8.66665 11.7018 8.96512 12.0003 9.33331 12.0003C9.7015 12.0003 9.99998 11.7018 9.99998 11.3337Z"
fill={color}
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.66665 3.33366V2.66699C4.66665 2.13656 4.87736 1.62785 5.25243 1.25278C5.62751 0.877706 6.13621 0.666992 6.66665 0.666992H9.33331C9.86375 0.666992 10.3725 0.877706 10.7475 1.25278C11.1226 1.62785 11.3333 2.13656 11.3333 2.66699V3.33366H14C14.3682 3.33366 14.6666 3.63214 14.6666 4.00033C14.6666 4.36852 14.3682 4.66699 14 4.66699H13.3333V13.3337C13.3333 13.8641 13.1226 14.3728 12.7475 14.7479C12.3725 15.1229 11.8637 15.3337 11.3333 15.3337H4.66665C4.13621 15.3337 3.62751 15.1229 3.25243 14.7479C2.87736 14.3728 2.66665 13.8641 2.66665 13.3337V4.66699H1.99998C1.63179 4.66699 1.33331 4.36852 1.33331 4.00033C1.33331 3.63214 1.63179 3.33366 1.99998 3.33366H4.66665ZM6.19524 2.19559C6.32027 2.07056 6.48984 2.00033 6.66665 2.00033H9.33331C9.51012 2.00033 9.67969 2.07056 9.80472 2.19559C9.92974 2.32061 9.99998 2.49018 9.99998 2.66699V3.33366H5.99998V2.66699C5.99998 2.49018 6.07022 2.32061 6.19524 2.19559ZM3.99998 4.66699V13.3337C3.99998 13.5105 4.07022 13.68 4.19524 13.8051C4.32027 13.9301 4.48984 14.0003 4.66665 14.0003H11.3333C11.5101 14.0003 11.6797 13.9301 11.8047 13.8051C11.9297 13.68 12 13.5105 12 13.3337V4.66699H3.99998Z"
fill={color}
/>
</svg>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MericoIconProps } from './types';

export const MericoIconExternalLink = ({ width, height }: MericoIconProps) => (
<svg width={width} height={height} viewBox="0 0 36 36" fill="none">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.5 10.5C7.10217 10.5 6.72064 10.658 6.43934 10.9393C6.15804 11.2206 6 11.6022 6 12V28.5C6 28.8978 6.15804 29.2794 6.43934 29.5607C6.72064 29.842 7.10218 30 7.5 30H24C24.3978 30 24.7794 29.842 25.0607 29.5607C25.342 29.2794 25.5 28.8978 25.5 28.5V19.5C25.5 18.6716 26.1716 18 27 18C27.8284 18 28.5 18.6716 28.5 19.5V28.5C28.5 29.6935 28.0259 30.8381 27.182 31.682C26.3381 32.5259 25.1935 33 24 33H7.5C6.30653 33 5.16193 32.5259 4.31802 31.682C3.47411 30.8381 3 29.6935 3 28.5V12C3 10.8065 3.47411 9.66193 4.31802 8.81802C5.16193 7.97411 6.30653 7.5 7.5 7.5H16.5C17.3284 7.5 18 8.17157 18 9C18 9.82843 17.3284 10.5 16.5 10.5H7.5Z"
fill="#3D3E45"
/>
<path
d="M32.8862 3.92582C32.8135 3.75021 32.7061 3.5856 32.5638 3.44253C32.5617 3.4404 32.5596 3.43828 32.5575 3.43616C32.2863 3.16658 31.9126 3 31.5 3H22.5C21.6716 3 21 3.67157 21 4.5C21 5.32843 21.6716 6 22.5 6H27.8787L13.9393 19.9393C13.3536 20.5251 13.3536 21.4749 13.9393 22.0607C14.5251 22.6464 15.4749 22.6464 16.0607 22.0607L30 8.12132V13.5C30 14.3284 30.6716 15 31.5 15C32.3284 15 33 14.3284 33 13.5V4.5C33 4.29662 32.9595 4.10268 32.8862 3.92582Z"
fill="#3D3E45"
/>
</svg>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './external-link';
export * from './play';
export * from './copy';
export * from './delete';
export * from './more';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { MericoIconProps } from './types';

export const MericoIconMore = ({ width, height }: MericoIconProps) => (
<svg viewBox="0 0 18 18" fill="none" width={width} height={height}>
<path
d="M7.5 3.75C7.5 2.92157 8.17157 2.25 9 2.25C9.82843 2.25 10.5 2.92157 10.5 3.75C10.5 4.57843 9.82843 5.25 9 5.25C8.17157 5.25 7.5 4.57843 7.5 3.75Z"
fill="#3D3E45"
/>
<path
d="M7.5 9C7.5 8.17157 8.17157 7.5 9 7.5C9.82843 7.5 10.5 8.17157 10.5 9C10.5 9.82843 9.82843 10.5 9 10.5C8.17157 10.5 7.5 9.82843 7.5 9Z"
fill="#3D3E45"
/>
<path
d="M9 12.75C8.17157 12.75 7.5 13.4216 7.5 14.25C7.5 15.0784 8.17157 15.75 9 15.75C9.82843 15.75 10.5 15.0784 10.5 14.25C10.5 13.4216 9.82843 12.75 9 12.75Z"
fill="#3D3E45"
/>
</svg>
);
Loading

0 comments on commit cf83109

Please sign in to comment.