Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support fetching description entity #735

Merged
merged 14 commits into from
May 8, 2023
45 changes: 37 additions & 8 deletions packages/console/src/components/Entities/EntityDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import { makeStyles, Theme } from '@material-ui/core/styles';
import classnames from 'classnames';
import { useCommonStyles } from 'components/common/styles';
import { WaitForData } from 'components/common/WaitForData';
import { useNamedEntity } from 'components/hooks/useNamedEntity';
import {
IdentifierScope,
NamedEntityMetadata,
ResourceIdentifier,
Variable,
} from 'models/Common/types';
Expand All @@ -20,7 +18,8 @@ import { TaskClosure } from 'models/Task/types';
import { executionFilterGenerator } from './generators';
import { Row } from './Row';
import t, { patternKey } from './strings';
import { entityStrings, entitySections } from './constants';
import {entityStrings, entitySections} from './constants';
import {useDescriptionEntityList} from "../hooks/useDescription";

const Skeleton = reactLoadingSkeleton;

Expand Down Expand Up @@ -96,9 +95,30 @@ export const EntityDescription: React.FC<{
}> = ({ id }) => {
const commonStyles = useCommonStyles();
const styles = useStyles();
const namedEntity = useNamedEntity(id);
const { metadata = {} as NamedEntityMetadata } = namedEntity.value;
const hasDescription = !!metadata.description;

const { resourceType } = id;
const sort = {
key: executionSortFields.createdAt,
direction: SortDirection.DESCENDING,
};

const baseFilters = React.useMemo(
() => executionFilterGenerator[resourceType](id),
[id, resourceType],
);

const descriptionEntities = useDescriptionEntityList(
{ ...id, version: '' },
{
sort,
filter: baseFilters,
limit: 1,
},
);

const descriptionEntity = descriptionEntities?.value?.[0]
const hasDescription = descriptionEntity?.longDescription.value.length !== 0;
const hasLink = !!descriptionEntity?.sourceCode?.link;
const sections = entitySections[id.resourceType];

return (
Expand All @@ -113,7 +133,7 @@ export const EntityDescription: React.FC<{
className={styles.description}
>
<WaitForData
{...namedEntity}
{...descriptionEntities}
spinnerVariant="none"
loadingComponent={Skeleton}
>
Expand All @@ -124,12 +144,21 @@ export const EntityDescription: React.FC<{
})}
>
{hasDescription
? metadata.description
? descriptionEntity?.longDescription?.value
: t(
patternKey('noDescription', entityStrings[id.resourceType]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason this bit doesn't seem to be working; ran a debugger and verified hasDescription is false but it doesn't seem to render the string?

Screenshot 2023-03-30 at 1 03 04 PM

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it.

image

image

)}
</span>
</Row>
{hasLink && (<Row title={t('githubLink')}>
<span>
{hasLink
?<a href={descriptionEntity?.sourceCode?.link} target="_blank" rel="noreferrer">{descriptionEntity?.sourceCode?.link}</a>
: t(
patternKey('noGithubLink', entityStrings[id.resourceType]),
)}
</span>
</Row>)}
</WaitForData>
{sections?.descriptionInputsAndOutputs && <InputsAndOuputs id={id} />}
</Typography>
Expand Down
2 changes: 2 additions & 0 deletions packages/console/src/components/Entities/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const str = {
noDescription_task: 'This task has no description.',
noSchedules_workflow: 'This workflow has no schedules.',
noSchedules_task: 'This task has no schedules.',
noDescription: 'No description found.',
allExecutionsChartTitle_workflow: 'All Executions in the Workflow',
allExecutionsChartTitle_task: 'All Executions in the Task',
allExecutionsChartTitle_launch_plan: 'All Executions Using Launch Plan',
Expand All @@ -22,6 +23,7 @@ const str = {
details_task: 'Task Details',
inputsFieldName: 'Inputs',
outputsFieldName: 'Outputs',
githubLink: 'Git',
imageFieldName: 'Image',
envVarsFieldName: 'Env Vars',
commandsFieldName: 'Commands',
Expand Down
7 changes: 6 additions & 1 deletion packages/console/src/components/Task/SimpleTaskInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ const VariablesList: React.FC<{ variables: Record<string, Variable> }> = ({
export const SimpleTaskInterface: React.FC<{ task: Task }> = ({ task }) => {
const { inputs = emptyVariables, outputs = emptyVariables } =
task.closure.compiledTask.template.interface || {};
const description = task.shortDescription || "No description found.";
return (
<div>
<DetailsGroup
labelWidthGridUnits={5}
labelWidthGridUnits={10}
items={[
{
name: 'inputs',
Expand All @@ -79,6 +80,10 @@ export const SimpleTaskInterface: React.FC<{ task: Task }> = ({ task }) => {
name: 'outputs',
content: <VariablesList variables={outputs.variables} />,
},
{
name: 'description',
content: <span>{description}</span>
}
]}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,16 @@ const SearchableWorkflowNameItem: React.FC<SearchableWorkflowNameItemProps> =
)}
</div>
</div>
<div className={styles.itemRow}>
<div className={styles.itemLabel}>Description</div>
<div className={styles.w100}>
{isLoading ? (
<Shimmer />
) : (
workflow?.description ?? <em>No description found.</em>
)}
</div>
</div>
<SearchableWorkflowNameItemActions
item={item}
setHideItem={setHideItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const useWorkflowInfoItem = ({
id?: Identifier | undefined;
inputs?: string | undefined;
outputs?: string | undefined;
description?: string | undefined;
};
isLoading: boolean;
error: unknown;
Expand Down Expand Up @@ -116,7 +117,8 @@ export const useWorkflowInfoItem = ({
const parsedOutputs = getOutputsForWorkflow(launchPlan);
const outputs =
parsedOutputs.length > 0 ? parsedOutputs.join(', ') : undefined;
return { id, inputs, outputs };
const description = workflow?.shortDescription && workflow?.shortDescription.length > 0 ? workflow.shortDescription : undefined
return { id, inputs, outputs, description};
},
{
staleTime: 1000 * 60 * 5,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { WorkflowGraph } from '../WorkflowGraph';
import graphData from './rich.json';

const graphDataClosure = graphData as unknown as CompiledWorkflowClosure;
const shortDescription = ""

const workflow: Workflow = {
closure: { compiledWorkflow: graphDataClosure },
Expand All @@ -19,6 +20,7 @@ const workflow: Workflow = {
name: 'test',
version: '1',
},
shortDescription: shortDescription,
};

const onNodeSelectionChanged = action('nodeSelected');
Expand Down
5 changes: 4 additions & 1 deletion packages/console/src/components/data/apiContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import * as LaunchAPI from 'models/Launch/api';
import * as ProjectAPI from 'models/Project/api';
import * as TaskAPI from 'models/Task/api';
import * as WorkflowAPI from 'models/Workflow/api';
import * as DescriptionEntityAPI from 'models/DescriptionEntity/api'
import * as React from 'react';

type APIFunctions = typeof CommonAPI &
typeof ExecutionAPI &
typeof LaunchAPI &
typeof ProjectAPI &
typeof TaskAPI &
typeof WorkflowAPI;
typeof WorkflowAPI &
typeof DescriptionEntityAPI;

export interface APIContextValue extends APIFunctions {
// use API functions only, for now
Expand All @@ -24,6 +26,7 @@ export const defaultAPIContextValue: APIContextValue = {
...ProjectAPI,
...TaskAPI,
...WorkflowAPI,
...DescriptionEntityAPI
};

/** Exposes all of the model layer api functions for use by data fetching
Expand Down
31 changes: 31 additions & 0 deletions packages/console/src/components/hooks/useDescription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {Identifier, IdentifierScope, RequestConfig} from "../../models";
import {useFetchableData} from "./useFetchableData";
import {getDescriptionEntity, listDescriptionEntities} from "../../models/DescriptionEntity/api";
import {DescriptionEntity} from "../../models/DescriptionEntity/types";
import {FetchableData} from "./types";
import {useAPIContext} from "../data/apiContext";
import {usePagination} from "./usePagination";


/** A hook for fetching a description entity */
export function useDescriptionEntity(id: Identifier): FetchableData<DescriptionEntity> {
const { getDescriptionEntity } = useAPIContext();
return useFetchableData<DescriptionEntity, Identifier>(
{
useCache: true,
debugName: 'DescriptionEntity',
defaultValue: {} as DescriptionEntity,
doFetch: async descriptionEntityId => (await getDescriptionEntity(descriptionEntityId)) as DescriptionEntity,
},
id,
);
}

/** A hook for fetching a paginated list of description entities */
export function useDescriptionEntityList(scope: IdentifierScope, config: RequestConfig) {
const { listDescriptionEntities } = useAPIContext();
return usePagination<DescriptionEntity, IdentifierScope>(
{ ...config, cacheItems: true, fetchArg: scope },
listDescriptionEntities,
);
}
1 change: 1 addition & 0 deletions packages/console/src/models/Common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const endpointPrefixes = {
recoverExecution: '/executions/recover',
setSignal: '/signals',
task: '/tasks',
descriptionEntity: 'description_entities',
taskExecution: '/task_executions',
taskExecutionChildren: '/children/task_executions',
workflow: '/workflows',
Expand Down
14 changes: 14 additions & 0 deletions packages/console/src/models/Common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,17 @@ export function makeNamedEntityPath({
name,
]).join('/');
}

export function makeDescriptionEntityPath(
prefix: string,
{ resourceType, project, domain, name, version }: Partial<Identifier>,
) {
const path = takeWhile([
resourceType,
project,
domain,
name,
decodeURIComponent(version || ''),
]).join('/');
return `${prefix}/${path}`;
}
30 changes: 30 additions & 0 deletions packages/console/src/models/DescriptionEntity/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Admin } from '@flyteorg/flyteidl-types';
import {
getAdminEntity,
} from 'models/AdminEntity/AdminEntity';
import { defaultPaginationConfig } from 'models/AdminEntity/constants';
import { RequestConfig } from 'models/AdminEntity/types';
import { Identifier, IdentifierScope } from 'models/Common/types';
import { DescriptionEntity } from './types';
import { makeDescriptionPath, descriptionEntityListTransformer } from './utils';

/** Fetches a list of `DescriptionEntity` records matching the provided `scope` */
export const listDescriptionEntities = (scope: IdentifierScope, config?: RequestConfig) =>
getAdminEntity(
{
path: makeDescriptionPath(scope),
messageType: Admin.DescriptionEntityList,
transform: descriptionEntityListTransformer,
},
{ ...defaultPaginationConfig, ...config },
);

/** Fetches an individual `DescriptionEntity` record */
export const getDescriptionEntity = (id: Identifier, config?: RequestConfig) =>
getAdminEntity<Admin.DescriptionEntity, DescriptionEntity>(
{
path: makeDescriptionPath(id),
messageType: Admin.DescriptionEntity,
},
config,
);
28 changes: 28 additions & 0 deletions packages/console/src/models/DescriptionEntity/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Admin } from '@flyteorg/flyteidl-types';
import { Identifier } from 'models/Common/types';


/** Optional link to source code used to define this entity */
export interface SourceCode extends Admin.ISourceCode {
link?: string
}

/** Full user description with formatting preserved */
export interface LongDescription extends Admin.IDescription {
value: string;
uri: string;
format: Admin.DescriptionFormat
iconLink?: string
}

/*
DescriptionEntity contains detailed description for the task/workflow.
Documentation could provide insight into the algorithms, business use case, etc
*/
export interface DescriptionEntity extends Admin.IDescriptionEntity {
id: Identifier;
shortDescription: string;
longDescription: LongDescription
sourceCode?: SourceCode
tags?: string[]
}
19 changes: 19 additions & 0 deletions packages/console/src/models/DescriptionEntity/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Admin } from '@flyteorg/flyteidl-types';
import { createPaginationTransformer } from 'models/AdminEntity/utils';
import { endpointPrefixes } from 'models/Common/constants';
import { IdentifierScope } from 'models/Common/types';
import { makeDescriptionEntityPath } from 'models/Common/utils';
import { DescriptionEntity } from './types';

/** Generate the correct path for retrieving a DescriptionEntity or list of DescriptionEntities based on the
* given scope.
*/
export function makeDescriptionPath(scope: IdentifierScope) {
return makeDescriptionEntityPath(endpointPrefixes.descriptionEntity, scope);
}

/** Transformer to coerce an `Admin.DescriptionEntityList` into a standard shape */
export const descriptionEntityListTransformer = createPaginationTransformer<
DescriptionEntity,
Admin.DescriptionEntityList
>('descriptionEntities');
2 changes: 2 additions & 0 deletions packages/console/src/models/Task/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface TaskTemplate extends Core.ITaskTemplate {
metadata?: TaskMetadata;
closure?: TaskClosure;
type: string;
shortDescription?: string;
}

/** An instance of a task which has been serialized into a `TaskClosure` */
Expand All @@ -44,4 +45,5 @@ export interface TaskClosure extends Admin.ITaskClosure {
export interface Task extends Admin.ITask {
id: Identifier;
closure: TaskClosure;
shortDescription?: string;
}
3 changes: 2 additions & 1 deletion packages/console/src/models/Workflow/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface CompiledWorkflowClosure extends Core.ICompiledWorkflowClosure {
tasks: CompiledTask[];
}

/** A serialized representation of all inforamtion about a specific workflow
/** A serialized representation of all information about a specific workflow
* version.
*/
export interface WorkflowClosure extends Admin.IWorkflowClosure {
Expand All @@ -37,6 +37,7 @@ export interface WorkflowClosure extends Admin.IWorkflowClosure {
export interface Workflow extends Admin.IWorkflow {
closure?: WorkflowClosure;
id: Identifier;
shortDescription?: string;
}

export type WorkflowId = Identifier;