Schema show page created
This commit is contained in:
parent
cb32dd25ae
commit
0e05605009
17 changed files with 206 additions and 98 deletions
|
@ -30,6 +30,8 @@ services:
|
|||
environment:
|
||||
ZOOKEEPER_CLIENT_PORT: 2181
|
||||
ZOOKEEPER_TICK_TIME: 2000
|
||||
ports:
|
||||
- 2181:2181
|
||||
|
||||
kafka0:
|
||||
image: confluentinc/cp-kafka:5.1.0
|
||||
|
|
11
kafka-ui-react-app/package-lock.json
generated
11
kafka-ui-react-app/package-lock.json
generated
|
@ -4813,9 +4813,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"bulma": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.8.2.tgz",
|
||||
"integrity": "sha512-vMM/ijYSxX+Sm+nD7Lmc1UgWDy2JcL2nTKqwgEqXuOMU+IGALbXd5MLt/BcjBAPLIx36TtzhzBcSnOP974gcqA=="
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.2.tgz",
|
||||
"integrity": "sha512-e14EF+3VSZ488yL/lJH0tR8mFWiEQVCMi/BQUMi2TGMBOk+zrDg4wryuwm/+dRSHJw0gMawp2tsW7X1JYUCE3A=="
|
||||
},
|
||||
"bulma-switch": {
|
||||
"version": "2.0.0",
|
||||
|
@ -11528,6 +11528,11 @@
|
|||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true
|
||||
},
|
||||
"json-formatter-js": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/json-formatter-js/-/json-formatter-js-2.3.4.tgz",
|
||||
"integrity": "sha512-gmAzYRtPRmYzeAT4T7+t3NhTF89JOAIioCVDddl9YDb3ls3kWcskirafw/MZGJaRhEU6fRimGJHl7CC7gaAI2Q=="
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
"dependencies": {
|
||||
"@types/react-datepicker": "^3.1.1",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"bulma": "^0.8.2",
|
||||
"bulma": "^0.9.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^2.16.1",
|
||||
"eslint-import-resolver-node": "^0.3.4",
|
||||
"eslint-import-resolver-typescript": "^2.3.0",
|
||||
"immer": "^8.0.1",
|
||||
"json-formatter-js": "^2.3.4",
|
||||
"lodash": "^4.17.20",
|
||||
"pretty-ms": "^6.0.1",
|
||||
"react": "^17.0.1",
|
||||
|
|
|
@ -1,31 +1,32 @@
|
|||
import { SchemaSubject } from 'generated-sources';
|
||||
import React from 'react';
|
||||
import { ClusterName } from 'redux/interfaces';
|
||||
import { ClusterName, SchemaName } from 'redux/interfaces';
|
||||
import JSONViewer from 'components/common/JSONViewer/JSONViewer';
|
||||
import Breadcrumb from '../../common/Breadcrumb/Breadcrumb';
|
||||
import DetailsItem from './DetailsItem';
|
||||
import { clusterSchemasPath } from '../../../lib/paths';
|
||||
import SchemaVersion from './SchemaVersion';
|
||||
|
||||
interface DetailsProps {
|
||||
schema: SchemaSubject;
|
||||
clusterName: ClusterName;
|
||||
schemaName: SchemaSubject['subject'];
|
||||
versions: string;
|
||||
subject: SchemaName;
|
||||
versions: SchemaSubject[];
|
||||
fetchSchemaVersions: (
|
||||
clusterName: ClusterName,
|
||||
schemaName: SchemaSubject['subject']
|
||||
schemaName: SchemaName
|
||||
) => void;
|
||||
}
|
||||
|
||||
const Details: React.FC<DetailsProps> = ({
|
||||
schema,
|
||||
clusterName,
|
||||
versions,
|
||||
fetchSchemaVersions,
|
||||
schemaName,
|
||||
subject,
|
||||
versions,
|
||||
}) => {
|
||||
React.useEffect(() => {
|
||||
fetchSchemaVersions(clusterName, schemaName);
|
||||
}, [fetchSchemaVersions, clusterName, schemaName]);
|
||||
fetchSchemaVersions(clusterName, subject);
|
||||
}, [fetchSchemaVersions, clusterName]);
|
||||
|
||||
return (
|
||||
<div className="section">
|
||||
|
@ -44,28 +45,84 @@ const Details: React.FC<DetailsProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
<div className="box">
|
||||
<table className="table is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Latest Version</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<DetailsItem schema={schema} />
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="level-left">
|
||||
<div className="level-item">
|
||||
<div className="mr-1">
|
||||
<b>Latest Version</b>
|
||||
</div>
|
||||
<div className="tag is-info is-light" title="Version">
|
||||
#{schema.version}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="button is-info is-small level-item"
|
||||
type="button"
|
||||
title="work in progress"
|
||||
disabled
|
||||
>
|
||||
Create Schema
|
||||
</button>
|
||||
<button
|
||||
className="button is-warning is-small level-item"
|
||||
type="button"
|
||||
title="work in progress"
|
||||
disabled
|
||||
>
|
||||
Update Schema
|
||||
</button>
|
||||
<button
|
||||
className="button is-danger is-small level-item"
|
||||
type="button"
|
||||
title="work in progress"
|
||||
disabled
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<div className="tile is-ancestor mt-1">
|
||||
<div className="tile is-4 is-parent">
|
||||
<div className="tile is-child">
|
||||
<table className="table is-fullwidth">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>{schema.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Subject</td>
|
||||
<td>{schema.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Compatibility</td>
|
||||
<td>{schema.compatibilityLevel}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="tile is-parent">
|
||||
<div className="tile is-child box py-1">
|
||||
<JSONViewer data={JSON.parse(schema.schema as string)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="box">
|
||||
<table className="table is-striped is-fullwidth">
|
||||
<table className="table is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Versions</th>
|
||||
<th>Version</th>
|
||||
<th>ID</th>
|
||||
<th>Schema</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{versions}</td>
|
||||
</tr>
|
||||
{versions
|
||||
.sort((a: SchemaSubject, b: SchemaSubject) => a.id - b.id)
|
||||
.map((version) => (
|
||||
<SchemaVersion key={version.id} version={version} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { ClusterName, RootState, TopicName } from 'redux/interfaces';
|
||||
import { ClusterName, RootState } from 'redux/interfaces';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import { getSchema, getSchemaList } from 'redux/reducers/schemas/selectors';
|
||||
import { getSchema, getSchemaVersions } from 'redux/reducers/schemas/selectors';
|
||||
import Details from './Details';
|
||||
import {
|
||||
fetchSchemasByClusterName,
|
||||
fetchSchemaVersions,
|
||||
} from '../../../redux/actions';
|
||||
import { fetchSchemaVersions } from '../../../redux/actions';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
|
@ -24,7 +21,7 @@ const mapStateToProps = (
|
|||
}: OwnProps
|
||||
) => ({
|
||||
schema: getSchema(state, subject),
|
||||
// versions: getSchemasVersions(state, subject),
|
||||
versions: getSchemaVersions(state),
|
||||
clusterName,
|
||||
subject,
|
||||
});
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import React from 'react';
|
||||
import { SchemaSubject } from 'generated-sources';
|
||||
|
||||
interface DetailsItemProps {
|
||||
schema: SchemaSubject;
|
||||
}
|
||||
|
||||
const DetailsItem: React.FC<DetailsItemProps> = ({ schema }) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{JSON.stringify(schema)}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetailsItem;
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react';
|
||||
import { SchemaSubject } from 'generated-sources';
|
||||
import JSONTree from 'react-json-tree';
|
||||
|
||||
interface SchemaVersionProps {
|
||||
version: SchemaSubject;
|
||||
}
|
||||
|
||||
const SchemaVersion: React.FC<SchemaVersionProps> = ({
|
||||
version: { version, id, schema },
|
||||
}) => {
|
||||
const themeJsonTree = {
|
||||
scheme: 'google',
|
||||
author: 'seth wright (http://sethawright.com)',
|
||||
base00: '#1d1f21',
|
||||
base01: '#282a2e',
|
||||
base02: '#373b41',
|
||||
base03: '#969896',
|
||||
base04: '#b4b7b4',
|
||||
base05: '#c5c8c6',
|
||||
base06: '#e0e0e0',
|
||||
base07: '#ffffff',
|
||||
base08: '#CC342B',
|
||||
base09: '#F96A38',
|
||||
base0A: '#FBA922',
|
||||
base0B: '#198844',
|
||||
base0C: '#3971ED',
|
||||
base0D: '#3971ED',
|
||||
base0E: '#A36AC7',
|
||||
base0F: '#3971ED',
|
||||
};
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>{version}</td>
|
||||
<td>{id}</td>
|
||||
<td className="py-0">
|
||||
<JSONTree data={JSON.parse(schema as string)} theme={themeJsonTree} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default SchemaVersion;
|
|
@ -16,11 +16,13 @@ const List: React.FC<ListProps> = ({ schemas }) => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Schema Name</th>
|
||||
<th>Version</th>
|
||||
<th>Compatibility</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{schemas.map(({ subject }) => (
|
||||
<ListItem subject={subject} />
|
||||
{schemas.map((subject) => (
|
||||
<ListItem key={subject.id} subject={subject} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { SchemaSubject } from 'generated-sources';
|
||||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
interface ListItemProps {
|
||||
subject?: string;
|
||||
subject: SchemaSubject;
|
||||
}
|
||||
|
||||
const ListItem: React.FC<ListItemProps> = ({ subject }) => {
|
||||
const ListItem: React.FC<ListItemProps> = ({
|
||||
subject: { subject, version, compatibilityLevel },
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
|
@ -18,6 +21,10 @@ const ListItem: React.FC<ListItemProps> = ({ subject }) => {
|
|||
{subject}
|
||||
</NavLink>
|
||||
</td>
|
||||
<td>{version}</td>
|
||||
<td>
|
||||
<span className="tag is-link">{compatibilityLevel}</span>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import JSONTree from 'react-json-tree';
|
||||
import theme from './themes/grayscale';
|
||||
|
||||
interface JSONViewerProps {
|
||||
data: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
const JSONViewer: React.FC<JSONViewerProps> = ({ data }) => (
|
||||
<JSONTree data={data} theme={theme} invertTheme={false} hideRoot />
|
||||
);
|
||||
|
||||
export default JSONViewer;
|
|
@ -0,0 +1,20 @@
|
|||
export default {
|
||||
scheme: 'grayscale',
|
||||
author: 'alexandre gavioli (https://github.com/alexx2/)',
|
||||
base00: '#101010',
|
||||
base01: '#252525',
|
||||
base02: '#464646',
|
||||
base03: '#525252',
|
||||
base04: '#ababab',
|
||||
base05: '#b9b9b9',
|
||||
base06: '#e3e3e3',
|
||||
base07: '#f7f7f7',
|
||||
base08: '#7c7c7c',
|
||||
base09: '#999999',
|
||||
base0A: '#a0a0a0',
|
||||
base0B: '#8e8e8e',
|
||||
base0C: '#868686',
|
||||
base0D: '#686868',
|
||||
base0E: '#747474',
|
||||
base0F: '#5e5e5e',
|
||||
};
|
|
@ -1,5 +1,4 @@
|
|||
import { ClusterName, TopicName } from 'redux/interfaces';
|
||||
import { SchemaSubject } from '../generated-sources';
|
||||
|
||||
const clusterPath = (clusterName: ClusterName) => `/ui/clusters/${clusterName}`;
|
||||
|
||||
|
@ -13,10 +12,6 @@ export const clusterConsumerGroupsPath = (clusterName: ClusterName) =>
|
|||
`${clusterPath(clusterName)}/consumer-groups`;
|
||||
export const clusterSchemasPath = (clusterName: ClusterName) =>
|
||||
`${clusterPath(clusterName)}/schemas`;
|
||||
// export const clusterSchemaPath = (
|
||||
// clusterName: ClusterName,
|
||||
// schemaName: string
|
||||
// ) => `${clusterSchemaPath(clusterName)}/${schemaName}/latest`;
|
||||
|
||||
export const clusterTopicPath = (
|
||||
clusterName: ClusterName,
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
Topic,
|
||||
TopicFormData,
|
||||
TopicConfig,
|
||||
SchemaSubject,
|
||||
} from 'generated-sources';
|
||||
import {
|
||||
ConsumerGroupID,
|
||||
|
@ -16,10 +15,10 @@ import {
|
|||
TopicMessageQueryParams,
|
||||
TopicFormFormattedParams,
|
||||
TopicFormDataRaw,
|
||||
SchemaName,
|
||||
} from 'redux/interfaces';
|
||||
|
||||
import { BASE_PARAMS } from 'lib/constants';
|
||||
import { flatten } from 'lodash';
|
||||
import * as actions from './actions';
|
||||
|
||||
const apiClientConf = new Configuration(BASE_PARAMS);
|
||||
|
@ -258,16 +257,8 @@ export const fetchSchemasByClusterName = (
|
|||
): PromiseThunk<void> => async (dispatch) => {
|
||||
dispatch(actions.fetchSchemasByClusterNameAction.request());
|
||||
try {
|
||||
const schemaNames = await apiClient.getSchemas({ clusterName });
|
||||
|
||||
// TODO: Remove me after API refactoring
|
||||
const schemas: SchemaSubject[][] = await Promise.all(
|
||||
schemaNames.map((schemaName) =>
|
||||
apiClient.getLatestSchema({ clusterName, schemaName })
|
||||
)
|
||||
);
|
||||
|
||||
dispatch(actions.fetchSchemasByClusterNameAction.success(flatten(schemas)));
|
||||
const schemas = await apiClient.getSchemas({ clusterName });
|
||||
dispatch(actions.fetchSchemasByClusterNameAction.success(schemas));
|
||||
} catch (e) {
|
||||
dispatch(actions.fetchSchemasByClusterNameAction.failure());
|
||||
}
|
||||
|
@ -275,28 +266,17 @@ export const fetchSchemasByClusterName = (
|
|||
|
||||
export const fetchSchemaVersions = (
|
||||
clusterName: ClusterName,
|
||||
schemaName: SchemaSubject['subject']
|
||||
subject: SchemaName
|
||||
// eslint-disable-next-line consistent-return
|
||||
): PromiseThunk<void> => async (dispatch) => {
|
||||
if (!schemaName) return Promise.resolve();
|
||||
if (!subject) return Promise.resolve();
|
||||
dispatch(actions.fetchSchemaVersionsAction.request());
|
||||
try {
|
||||
const versionIds = await apiClient.getSchemaVersions({
|
||||
const versions = await apiClient.getAllVersionsBySubject({
|
||||
clusterName,
|
||||
schemaName,
|
||||
subject,
|
||||
});
|
||||
|
||||
console.log(versionIds);
|
||||
|
||||
const versions: SchemaSubject[][] = await Promise.all(
|
||||
versionIds.map((version) =>
|
||||
apiClient.getSchemaByVersion({ clusterName, schemaName, version })
|
||||
)
|
||||
);
|
||||
|
||||
console.log(versions);
|
||||
|
||||
dispatch(actions.fetchSchemaVersionsAction.success(flatten(versions)));
|
||||
dispatch(actions.fetchSchemaVersionsAction.success(versions));
|
||||
} catch (e) {
|
||||
dispatch(actions.fetchSchemaVersionsAction.failure());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { SchemaSubject } from 'generated-sources';
|
||||
|
||||
export type SchemaName = SchemaSubject['subject'];
|
||||
|
||||
export interface SchemasState {
|
||||
byName: { [subject: string]: SchemaSubject };
|
||||
allNames: string[];
|
||||
allNames: SchemaName[];
|
||||
currentSchemaVersions: SchemaSubject[];
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ const schemasState = ({ schemas }: RootState): SchemasState => schemas;
|
|||
|
||||
const getAllNames = (state: RootState) => schemasState(state).allNames;
|
||||
const getSchemaMap = (state: RootState) => schemasState(state).byName;
|
||||
// const getSchemaVersion = (state: RootState) => schemasState(state).versions;
|
||||
|
||||
const getSchemaListFetchingStatus = createFetchingSelector(
|
||||
'GET_CLUSTER_SCHEMAS'
|
||||
|
@ -25,7 +24,7 @@ export const getSchemaList = createSelector(
|
|||
if (!isFetched) {
|
||||
return [];
|
||||
}
|
||||
return allNames.map((subject) => byName[subject]);
|
||||
return allNames.map((subject) => byName[subject as string]);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -37,10 +36,7 @@ export const getSchema = createSelector(
|
|||
(schemas, subject) => schemas[subject]
|
||||
);
|
||||
|
||||
// export const getSchemasVersions = createSelector(
|
||||
// getSchemaVersion,
|
||||
// getSchema,
|
||||
// (versions, subject) => {
|
||||
// return versions.map((version) => subject['version'])
|
||||
// }
|
||||
// );
|
||||
export const getSchemaVersions = createSelector(
|
||||
schemasState,
|
||||
({ currentSchemaVersions }) => currentSchemaVersions
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@import "../../node_modules/bulma/sass/base/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/elements/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/form/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/helpers/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/components/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/grid/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/layout/_all.sass";
|
||||
|
|
0
testSchema
Normal file
0
testSchema
Normal file
Loading…
Add table
Reference in a new issue