Skip to content

Commit

Permalink
Add ability to show error message for the tiles on the enabled applic…
Browse files Browse the repository at this point in the history
…ations page
  • Loading branch information
yzhao583 committed Jan 14, 2025
1 parent 95d2b64 commit c0380fd
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 22 deletions.
4 changes: 3 additions & 1 deletion backend/src/routes/api/integrations/nim/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createNIMAccount,
manageNIMSecret,
getNIMAccount,
errorMsgList,
apiKeyValidationStatus,
apiKeyValidationTimestamp,
isAppEnabled,
Expand All @@ -25,13 +26,14 @@ module.exports = async (fastify: KubeFastifyInstance) => {
const isEnabled = isAppEnabled(response);
const keyValidationStatus: string = apiKeyValidationStatus(response);
const keyValidationTimestamp: string = apiKeyValidationTimestamp(response);
const errorMsg: string = errorMsgList(response)[0];
reply.send({
isInstalled: true,
isEnabled: isEnabled,
variablesValidationStatus: keyValidationStatus,
variablesValidationTimestamp: keyValidationTimestamp,
canInstall: !isEnabled,
error: '',
error: errorMsg,
});
} else {
// Not installed
Expand Down
7 changes: 7 additions & 0 deletions backend/src/routes/api/integrations/nim/nimUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { KubeFastifyInstance, NIMAccountKind, SecretKind } from '../../../../typ
const NIM_SECRET_NAME = 'nvidia-nim-access';
const NIM_ACCOUNT_NAME = 'odh-nim-account';

export const errorMsgList = (app: NIMAccountKind): string[] => {
const conditions = app?.status?.conditions || [];
return conditions
.filter((condition) => condition.status === 'False')
.map((condition) => condition.message);
};

export const apiKeyValidationTimestamp = (app: NIMAccountKind): string => {
const conditions = app?.status?.conditions || [];
const apiKeyCondition = conditions.find((condition) => condition.type === 'APIKeyValidation');
Expand Down
45 changes: 28 additions & 17 deletions frontend/src/components/OdhAppCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
MenuToggle,
DropdownList,
Label,
capitalize,
} from '@patternfly/react-core';
import { css } from '@patternfly/react-styles';
import { EllipsisVIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
import { EllipsisVIcon, ExclamationCircleIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
import { OdhApplication } from '~/types';
import { getLaunchStatus, launchQuickStart } from '~/utilities/quickStartUtils';
import EnableModal from '~/pages/exploreApplication/EnableModal';
Expand Down Expand Up @@ -141,19 +142,23 @@ const OdhAppCard: React.FC<OdhAppCardProps> = ({ odhApp }) => {

const popoverBodyContent = (hide: () => void) => (
<div>
Subscription is no longer valid. To validate click&nbsp;
<Button
isInline
variant="link"
onClick={() => {
hide();
setEnableOpen(true);
}}
>
here.
</Button>
{!isInternalRouteIntegrationsApp(odhApp.spec.internalRoute) ? (
{isInternalRouteIntegrationsApp(odhApp.spec.internalRoute) ? (
<>
{odhApp.spec.error ? `${capitalize(odhApp.spec.error)}.` : ''} Contact your administrator.
</>
) : (
<>
Subscription is no longer valid. To validate click&nbsp;
<Button
isInline
variant="link"
onClick={() => {
hide();
setEnableOpen(true);
}}
>
here.
</Button>
To remove card click&nbsp;
<Button
isInline
Expand All @@ -167,17 +172,23 @@ const OdhAppCard: React.FC<OdhAppCardProps> = ({ odhApp }) => {
</Button>
.
</>
) : null}
)}
</div>
);

const disabledPopover = (
<Popover
headerContent={<div className="odh-card__disabled-popover-title">Application disabled</div>}
headerContent={
<div className="odh-card__disabled-popover-title">
Enable {odhApp.spec.displayName} failed
</div>
}
bodyContent={popoverBodyContent}
position="bottom"
position="right"
headerIcon={<ExclamationCircleIcon />}
alertSeverityVariant="danger"
>
<Button variant="plain" className="odh-card__disabled-text">
<Button variant="link" className="odh-card__disabled-text">
Disabled
</Button>
</Popover>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/OdhCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
}

&__disabled-popover-title {
font-size: var(--pf-t--global--font--size--heading--h6);
font-size: var(--pf-t--global--font--size--heading--h7);
color: var(--pf-t--global--text--color--status--danger--default);
}

&__explore-badges {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export type OdhApplication = {
};
featureFlag?: string;
internalRoute?: string;
error?: string;
};
};

Expand Down
21 changes: 18 additions & 3 deletions frontend/src/utilities/useWatchIntegrationComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,19 @@ export const useWatchIntegrationComponents = (
);

if (response.error) {
// TODO: Show the error somehow
setNewComponents(
componentList.filter((app) => app.metadata.name !== component.metadata.name),
const updatedComponents = componentList.map((app) =>
app.metadata.name === component.metadata.name
? {
...app,
spec: {
...app.spec,
isEnabled: false,
error: response.error,
},
}
: app,
);
setNewComponents(updatedComponents);
} else {
const updatedComponents = componentList
.filter(
Expand All @@ -69,21 +78,27 @@ export const useWatchIntegrationComponents = (

React.useEffect(() => {
let watchHandle: ReturnType<typeof setTimeout>;
let isMounted = true;

if (integrationComponents && components) {
if (integrationComponents.length === 0) {
setIsIntegrationComponentsChecked(true);
setNewComponents(components);
} else {
const watchComponents = () => {
if (!isMounted) return;

Check failure on line 89 in frontend/src/utilities/useWatchIntegrationComponents.tsx

View workflow job for this annotation

GitHub Actions / Tests (18.x)

Expected { after 'if' condition
updateComponentEnablementStatus(integrationComponents, components).then(() => {
if (!isMounted) return;

Check failure on line 91 in frontend/src/utilities/useWatchIntegrationComponents.tsx

View workflow job for this annotation

GitHub Actions / Tests (18.x)

Expected { after 'if' condition
setIsIntegrationComponentsChecked(true);
watchHandle = setTimeout(watchComponents, POLL_INTERVAL);
});
};
watchComponents();
}
}

Check failure on line 99 in frontend/src/utilities/useWatchIntegrationComponents.tsx

View workflow job for this annotation

GitHub Actions / Tests (18.x)

Delete `····`
return () => {
isMounted = false;
clearTimeout(watchHandle);
};
}, [components, integrationComponents]);
Expand Down

0 comments on commit c0380fd

Please sign in to comment.