Skip to content

Commit 80f6d93

Browse files
authored
[UI] Convert all REST API calls to use the SDK (#4818)
* Convert all methods in useAdminService to new sdk * Convert search, system, and user services to the new SDK * Converted all REST calls to the new SDK * Fix error handling
1 parent c0122ad commit 80f6d93

File tree

82 files changed

+514
-930
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+514
-930
lines changed

typescript-sdk/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules
22
dist
33
.kiota
4+
.vite
45
generated-client

ui/ui-app/src/app/components/downloadArtifacts/DownloadArtifacts.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FunctionComponent } from "react";
22
import { Button, ButtonVariant } from "@patternfly/react-core";
33
import { AdminService, useAdminService } from "@services/useAdminService.ts";
4-
import { DownloadRef } from "@models/downloadRef.model.ts";
4+
import { DownloadRef } from "@sdk/lib/generated-client/models";
55

66

77
export type DownloadArtifactsProps = {
@@ -23,7 +23,7 @@ export const DownloadArtifacts: FunctionComponent<DownloadArtifactsProps> = (pro
2323
const downloadArtifacts = () => {
2424
const { fileName } = props;
2525
admin.exportAs(fileName).then((response: DownloadRef) => {
26-
generateDownloadLink(fileName, response?.href);
26+
generateDownloadLink(fileName, response?.href || "");
2727
});
2828
};
2929

ui/ui-app/src/app/components/errorPage/AccessErrorPage.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const AccessErrorPage: FunctionComponent<ErrorPageProps> = () => {
2929
<EmptyState>
3030
<EmptyStateHeader titleText="Access permissions needed" headingLevel="h4" icon={<EmptyStateIcon icon={LockedIcon} />} />
3131
<EmptyStateBody>
32-
To access this Registry instance, contact your organization administrators.
32+
To access this Registry instance, contact your organization administrator.
3333
</EmptyStateBody>
3434
<EmptyStateFooter>
3535
<EmptyStateActions>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.centerizer {
2+
text-align: center;
3+
}
4+
5+
.centerizer > div {
6+
display: inline-block;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { FunctionComponent } from "react";
2+
import "./ConnectionFailedErrorPage.css";
3+
import {
4+
Button,
5+
EmptyState,
6+
EmptyStateActions,
7+
EmptyStateBody,
8+
EmptyStateFooter,
9+
EmptyStateHeader,
10+
EmptyStateIcon,
11+
PageSection,
12+
PageSectionVariants
13+
} from "@patternfly/react-core";
14+
import { NetworkIcon } from "@patternfly/react-icons";
15+
import { ErrorPageProps } from "./ErrorPage.tsx";
16+
17+
18+
export const ConnectionFailedErrorPage: FunctionComponent<ErrorPageProps> = () => {
19+
20+
const reload = (): void => {
21+
window.location.reload();
22+
};
23+
24+
return (
25+
<React.Fragment>
26+
<PageSection className="ps_error" variant={PageSectionVariants.light}>
27+
<div className="centerizer">
28+
<EmptyState>
29+
<EmptyStateHeader titleText="Connection failed" headingLevel="h4" icon={<EmptyStateIcon icon={NetworkIcon} />} />
30+
<EmptyStateBody>
31+
Connection to the Registry server failed (could not reach the server). Please
32+
check your connection and try again, or report this error to an admin.
33+
</EmptyStateBody>
34+
<EmptyStateFooter>
35+
<EmptyStateActions>
36+
</EmptyStateActions>
37+
<EmptyStateActions>
38+
<Button variant="link"
39+
data-testid="error-btn-reload"
40+
onClick={reload}>Reload the page</Button>
41+
</EmptyStateActions>
42+
</EmptyStateFooter>
43+
</EmptyState>
44+
</div>
45+
</PageSection>
46+
</React.Fragment>
47+
);
48+
49+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.centerizer {
2+
text-align: center;
3+
}
4+
5+
.centerizer > div {
6+
display: inline-block;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { FunctionComponent } from "react";
2+
import "./NotFoundErrorPage.css";
3+
import {
4+
Button,
5+
EmptyState,
6+
EmptyStateActions,
7+
EmptyStateBody,
8+
EmptyStateFooter,
9+
EmptyStateHeader,
10+
EmptyStateIcon,
11+
PageSection,
12+
PageSectionVariants
13+
} from "@patternfly/react-core";
14+
import { QuestionCircleIcon } from "@patternfly/react-icons";
15+
import { ErrorPageProps } from "./ErrorPage.tsx";
16+
17+
18+
export const NotFoundErrorPage: FunctionComponent<ErrorPageProps> = () => {
19+
20+
const navigateBack = (): void => {
21+
window.history.back();
22+
};
23+
24+
return (
25+
<React.Fragment>
26+
<PageSection className="ps_error" variant={PageSectionVariants.light}>
27+
<div className="centerizer">
28+
<EmptyState>
29+
<EmptyStateHeader titleText="Resource not found" headingLevel="h4" icon={<EmptyStateIcon icon={QuestionCircleIcon} />} />
30+
<EmptyStateBody>
31+
The resource you were looking for could not be found. Perhaps it
32+
was deleted?
33+
</EmptyStateBody>
34+
<EmptyStateFooter>
35+
<EmptyStateActions>
36+
</EmptyStateActions>
37+
<EmptyStateActions>
38+
<Button variant="link"
39+
data-testid="error-btn-back"
40+
onClick={navigateBack}>Return to previous page</Button>
41+
</EmptyStateActions>
42+
</EmptyStateFooter>
43+
</EmptyState>
44+
</div>
45+
</PageSection>
46+
</React.Fragment>
47+
);
48+
49+
};
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export * from "./ErrorPage.tsx";
22
export * from "./AccessErrorPage.tsx";
33
export * from "./RateLimitErrorPage.tsx";
4+
export * from "./ConnectionFailedErrorPage.tsx";
5+
export * from "./NotFoundErrorPage.tsx";
46

ui/ui-app/src/app/components/modals/CreateArtifactForm.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ import { ExclamationCircleIcon } from "@patternfly/react-icons";
1616
import { If, ObjectSelect, UrlUpload } from "@apicurio/common-ui-components";
1717
import { UrlService, useUrlService } from "@services/useUrlService.ts";
1818
import { ArtifactTypesService, useArtifactTypesService } from "@services/useArtifactTypesService.ts";
19-
import { CreateArtifact } from "@models/createArtifact.model.ts";
2019
import { detectContentType } from "@utils/content.utils.ts";
2120
import { ContentTypes } from "@models/contentTypes.model.ts";
2221
import { isStringEmptyOrUndefined } from "@utils/string.utils.ts";
22+
import { CreateArtifact } from "@sdk/lib/generated-client/models";
2323

2424
/**
2525
* Properties
@@ -125,7 +125,7 @@ export const CreateArtifactForm: FunctionComponent<CreateArtifactFormProps> = (p
125125
const fireOnChange = (): void => {
126126
const data: CreateArtifact = {
127127
artifactId,
128-
type: artifactType
128+
artifactType
129129
};
130130
if (!isStringEmptyOrUndefined(content)) {
131131
data.firstVersion = {

ui/ui-app/src/app/components/modals/CreateArtifactModal.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FunctionComponent, useEffect, useState } from "react";
22
import { Button, Modal } from "@patternfly/react-core";
3-
import { CreateArtifact } from "@models/createArtifact.model.ts";
43
import { CreateArtifactForm } from "@app/components";
4+
import { CreateArtifact } from "@sdk/lib/generated-client/models";
55

66
const EMPTY_FORM_DATA: CreateArtifact = {
77
};

ui/ui-app/src/app/components/modals/CreateGroupModal.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FunctionComponent, useEffect, useState } from "react";
22
import { Button, Form, FormGroup, Grid, GridItem, Modal, TextInput } from "@patternfly/react-core";
3-
import { CreateGroup } from "@models/createGroup.model.ts";
3+
import { CreateGroup } from "@sdk/lib/generated-client/models";
44

55

66
/**

ui/ui-app/src/app/components/modals/CreateVersionModal.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { FunctionComponent, useEffect, useState } from "react";
22
import { Button, FileUpload, Form, FormGroup, Modal, TextInput } from "@patternfly/react-core";
3-
import { CreateVersion } from "@models/createVersion.model.ts";
43
import { isStringEmptyOrUndefined } from "@utils/string.utils.ts";
54
import { detectContentType } from "@utils/content.utils.ts";
5+
import { CreateVersion } from "@sdk/lib/generated-client/models";
66

77

88
/**

ui/ui-app/src/app/components/modals/EditMetaDataModal.tsx

+14-8
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,37 @@ import {
1212
} from "@patternfly/react-core";
1313
import { If } from "@apicurio/common-ui-components";
1414
import { ArtifactLabel, LabelsFormGroup } from "@app/components";
15+
import { Labels } from "@sdk/lib/generated-client/models";
16+
import { labelsToAny } from "@utils/rest.utils.ts";
1517

1618

1719
export type MetaData = {
1820
name?: string;
1921
description: string;
20-
labels: { [key: string]: string|undefined };
22+
labels: Labels;
2123
}
2224

2325

24-
function labelsToList(labels: { [key: string]: string|undefined }): ArtifactLabel[] {
25-
return Object.keys(labels).filter((key) => key !== undefined).map(key => {
26+
function labelsToList(labels: Labels): ArtifactLabel[] {
27+
const theLabels: any = labelsToAny(labels);
28+
delete theLabels["additionalData"];
29+
return Object.keys(theLabels).filter((key) => key !== undefined).map(key => {
2630
return {
2731
name: key,
28-
value: labels[key],
32+
value: theLabels[key] as string,
2933
nameValidated: "default",
3034
valueValidated: "default"
3135
};
3236
});
3337
}
3438

35-
function listToLabels(labels: ArtifactLabel[]): { [key: string]: string|undefined } {
36-
const rval: { [key: string]: string|undefined } = {};
39+
function listToLabels(labels: ArtifactLabel[]): Labels {
40+
const rval: Labels = {
41+
additionalData: {}
42+
};
3743
labels.forEach(label => {
3844
if (label.name) {
39-
rval[label.name] = label.value;
45+
rval.additionalData![label.name] = label.value;
4046
}
4147
});
4248
return rval;
@@ -50,7 +56,7 @@ export type EditMetaDataModalProps = {
5056
entityType: string;
5157
name?: string;
5258
description: string;
53-
labels: { [key: string]: string|undefined };
59+
labels: Labels;
5460
isOpen: boolean;
5561
onClose: () => void;
5662
onEditMetaData: (metaData: MetaData) => void;

ui/ui-app/src/app/pages/PageErrorHandler.tsx

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import React, { FunctionComponent } from "react";
2-
import { AccessErrorPage, ErrorPage, RateLimitErrorPage } from "@app/components";
2+
import {
3+
AccessErrorPage,
4+
ConnectionFailedErrorPage,
5+
ErrorPage,
6+
NotFoundErrorPage,
7+
RateLimitErrorPage
8+
} from "@app/components";
39
import { PageError } from "@app/pages/PageError.ts";
410

511
/**
@@ -20,11 +26,17 @@ export const PageErrorHandler: FunctionComponent<PageErrorHandlerProps> = (props
2026
const isError = (): boolean => {
2127
return props.error !== undefined;
2228
};
29+
const isFetchError = (): boolean => {
30+
return props.error !== undefined && props.error.error instanceof TypeError && (props.error.error as TypeError).message.includes("fetch");
31+
};
32+
const is404Error = (): boolean => {
33+
return props.error && props.error.error.error_code && (props.error.error.error_code == 404);
34+
};
2335
const is403Error = (): boolean => {
24-
return props.error && props.error.error.status && (props.error.error.status == 403);
36+
return props.error && props.error.error.error_code && (props.error.error.error_code == 403);
2537
};
2638
const is419Error = (): boolean => {
27-
return props.error && props.error.error.status && (props.error.error.status == 419);
39+
return props.error && props.error.error.error_code && (props.error.error.error_code == 419);
2840
};
2941

3042
if (isError()) {
@@ -36,6 +48,14 @@ export const PageErrorHandler: FunctionComponent<PageErrorHandlerProps> = (props
3648
return (
3749
<RateLimitErrorPage error={props.error}/>
3850
);
51+
} else if (is404Error()) {
52+
return (
53+
<NotFoundErrorPage error={props.error}/>
54+
);
55+
} else if (isFetchError()) {
56+
return (
57+
<ConnectionFailedErrorPage error={props.error}/>
58+
);
3959
} else {
4060
return (
4161
<ErrorPage error={props.error}/>

ui/ui-app/src/app/pages/artifact/ArtifactPage.tsx

+4-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { FunctionComponent, useEffect, useState } from "react";
22
import "./ArtifactPage.css";
33
import { Breadcrumb, BreadcrumbItem, PageSection, PageSectionVariants, Tab, Tabs } from "@patternfly/react-core";
44
import { Link, useParams } from "react-router-dom";
5-
import { ArtifactMetaData } from "@models/artifactMetaData.model.ts";
65
import { PageDataLoader, PageError, PageErrorHandler, toPageError } from "@app/pages";
76
import {
87
ChangeOwnerModal,
@@ -21,10 +20,8 @@ import {
2120
ArtifactPageHeader,
2221
VersionsTabContent
2322
} from "@app/pages/artifact/components";
24-
import { SearchedVersion } from "@models/searchedVersion.model.ts";
25-
import { CreateVersion } from "@models/createVersion.model.ts";
2623
import { ApiError } from "@models/apiError.model.ts";
27-
import { Rule, RuleType } from "@sdk/lib/generated-client/models";
24+
import { ArtifactMetaData, CreateVersion, Rule, RuleType, SearchedVersion } from "@sdk/lib/generated-client/models";
2825

2926

3027
export type ArtifactPageProps = {
@@ -183,7 +180,7 @@ export const ArtifactPage: FunctionComponent<ArtifactPageProps> = () => {
183180
const onViewVersion = (version: SearchedVersion): void => {
184181
const groupId: string = encodeURIComponent(artifact?.groupId || "default");
185182
const artifactId: string = encodeURIComponent(artifact?.artifactId || "");
186-
const ver: string = encodeURIComponent(version.version);
183+
const ver: string = encodeURIComponent(version.version!);
187184
appNavigation.navigateTo(`/explore/${groupId}/${artifactId}/${ver}`);
188185
};
189186

@@ -218,8 +215,8 @@ export const ArtifactPage: FunctionComponent<ArtifactPageProps> = () => {
218215

219216
groups.createArtifactVersion(groupId as string, artifactId as string, data).then(versionMetaData => {
220217
const groupId: string = encodeURIComponent(versionMetaData.groupId ? versionMetaData.groupId : "default");
221-
const artifactId: string = encodeURIComponent(versionMetaData.artifactId);
222-
const version: string = encodeURIComponent(versionMetaData.version);
218+
const artifactId: string = encodeURIComponent(versionMetaData.artifactId!);
219+
const version: string = encodeURIComponent(versionMetaData.version!);
223220
const artifactVersionLocation: string = `/explore/${groupId}/${artifactId}/${version}`;
224221
logger.info("[ArtifactPage] Artifact version successfully created. Redirecting to details: ", artifactVersionLocation);
225222
pleaseWait(false);

ui/ui-app/src/app/pages/artifact/components/pageheader/ArtifactPageHeader.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { FunctionComponent } from "react";
22
import "./ArtifactPageHeader.css";
33
import { Button, Flex, FlexItem, Text, TextContent, TextVariants } from "@patternfly/react-core";
44
import { IfAuth, IfFeature } from "@app/components";
5-
import { ArtifactMetaData } from "@models/artifactMetaData.model.ts";
65
import { If } from "@apicurio/common-ui-components";
6+
import { ArtifactMetaData } from "@sdk/lib/generated-client/models";
77

88

99
/**

ui/ui-app/src/app/pages/artifact/components/tabs/ArtifactInfoTabContent.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import {
1919
} from "@patternfly/react-core";
2020
import { PencilAltIcon } from "@patternfly/react-icons";
2121
import { FromNow, If } from "@apicurio/common-ui-components";
22-
import { ArtifactMetaData } from "@models/artifactMetaData.model.ts";
2322
import { isStringEmptyOrUndefined } from "@utils/string.utils.ts";
24-
import { Rule } from "@sdk/lib/generated-client/models";
23+
import { ArtifactMetaData, Rule } from "@sdk/lib/generated-client/models";
24+
import { labelsToAny } from "@utils/rest.utils.ts";
2525

2626
/**
2727
* Properties
@@ -49,14 +49,16 @@ export const ArtifactInfoTabContent: FunctionComponent<ArtifactInfoTabContentPro
4949
return props.artifact.name || "No name";
5050
};
5151

52+
const labels: any = labelsToAny(props.artifact.labels);
53+
5254
return (
5355
<div className="artifact-tab-content">
5456
<div className="artifact-basics">
5557
<Card>
5658
<CardTitle>
5759
<div className="title-and-type">
5860
<Flex>
59-
<FlexItem className="type"><ArtifactTypeIcon artifactType={props.artifact.artifactType} /></FlexItem>
61+
<FlexItem className="type"><ArtifactTypeIcon artifactType={props.artifact.artifactType!} /></FlexItem>
6062
<FlexItem className="title">Artifact metadata</FlexItem>
6163
<FlexItem className="actions" align={{ default: "alignRight" }}>
6264
<IfAuth isDeveloper={true}>
@@ -124,9 +126,9 @@ export const ArtifactInfoTabContent: FunctionComponent<ArtifactInfoTabContentPro
124126
</DescriptionListGroup>
125127
<DescriptionListGroup>
126128
<DescriptionListTerm>Labels</DescriptionListTerm>
127-
{!props.artifact.labels || !Object.keys(props.artifact.labels).length ?
129+
{!labels || !Object.keys(labels).length ?
128130
<DescriptionListDescription data-testid="artifact-details-labels" className="empty-state-text">No labels</DescriptionListDescription> :
129-
<DescriptionListDescription data-testid="artifact-details-labels">{Object.entries(props.artifact.labels).map(([key, value]) =>
131+
<DescriptionListDescription data-testid="artifact-details-labels">{Object.entries(labels).map(([key, value]) =>
130132
<Label key={`label-${key}`} color="purple" style={{ marginBottom: "2px", marginRight: "5px" }}>
131133
<Truncate className="label-truncate" content={`${key}=${value}`} />
132134
</Label>

0 commit comments

Comments
 (0)