Skip to content

Commit

Permalink
Add support fetching description entity (#735)
Browse files Browse the repository at this point in the history
* Add Description entity

Signed-off-by: Kevin Su <[email protected]>

* Add Description entity

Signed-off-by: Kevin Su <[email protected]>

* nit

Signed-off-by: Kevin Su <[email protected]>

* nit

Signed-off-by: Kevin Su <[email protected]>

* nit

Signed-off-by: Kevin Su <[email protected]>

* address comment

Signed-off-by: Kevin Su <[email protected]>

* test ci

Signed-off-by: Kevin Su <[email protected]>

* test ci

Signed-off-by: Kevin Su <[email protected]>

* test ci

Signed-off-by: Kevin Su <[email protected]>

* test ci

Signed-off-by: Kevin Su <[email protected]>

* test ci

Signed-off-by: Kevin Su <[email protected]>

---------

Signed-off-by: Kevin Su <[email protected]>
Co-authored-by: Jason Porter <[email protected]>
Signed-off-by: Carina Ursu <[email protected]>
  • Loading branch information
2 people authored and ursucarina committed May 10, 2023
1 parent 76ed376 commit 687cdb9
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 12 deletions.
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]),
)}
</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 @@ -14,6 +14,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;

0 comments on commit 687cdb9

Please sign in to comment.