Skip to content

Commit

Permalink
Merge branch 'master' into add-clipboard-write-iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
eapolinario authored Apr 2, 2024
2 parents e61197a + 7aabb32 commit 88778e2
Show file tree
Hide file tree
Showing 33 changed files with 2,227 additions and 596 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import styled from '@mui/system/styled';
import isNil from 'lodash/isNil';
import Grid from '@mui/material/Grid';
import { Identifier, ResourceIdentifier, ResourceType } from '../../models/Common/types';
import { LaunchForm } from '../Launch/LaunchForm/LaunchForm';
import { useEscapeKey } from '../hooks/useKeyListener';
import { LaunchTaskFormProps, LaunchWorkflowFormProps } from '../Launch/LaunchForm/types';
import t, { patternKey } from './strings';
import { entityStrings } from './constants';
import BreadcrumbTitleActions from '../Breadcrumbs/components/BreadcrumbTitleActions';
import { LaunchPlanDetailsHeader } from '../LaunchPlan/components/LaunchPlanDetailsHeader';

const EntityDetailsHeaderContainer = styled('div')(({ theme }) => ({
'.headerContainer': {
Expand Down Expand Up @@ -88,24 +90,33 @@ export const EntityDetailsHeader: React.FC<EntityDetailsHeaderProps> = ({
onCancelLaunch();
});

const showLaunchPlanDetails = id.resourceType === ResourceType.LAUNCH_PLAN;

return (
<EntityDetailsHeaderContainer>
<div>
<BreadcrumbTitleActions>
{launchable ? (
<Button
color="primary"
id="launch-workflow"
onClick={() => {
setShowLaunchForm(true);
}}
variant="contained"
>
{t(patternKey('launchStrings', entityStrings[id.resourceType]))}
</Button>
) : (
<></>
)}
<Grid
container
direction="row"
sx={showLaunchPlanDetails ? { maxWidth: '654px', width: '100%' } : {}}
>
{launchable ? (
<Button
color="primary"
id="launch-workflow"
onClick={() => {
setShowLaunchForm(true);
}}
variant="contained"
>
{t(patternKey('launchStrings', entityStrings[id.resourceType]))}
</Button>
) : (
<></>
)}
{showLaunchPlanDetails ? <LaunchPlanDetailsHeader id={id} /> : null}
</Grid>
</BreadcrumbTitleActions>
</div>
{launchable ? (
Expand Down
195 changes: 85 additions & 110 deletions packages/oss-console/src/components/Entities/EntitySchedules.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React from 'react';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
import Typography from '@mui/material/Typography';
Expand All @@ -11,30 +11,23 @@ import styled from '@mui/system/styled';
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton';
import { SortDirection } from '@clients/common/types/adminEntityTypes';
import { useQueryClient } from 'react-query';
import { makeListDescriptionEntitiesQuery } from '@clients/oss-console/queries/descriptionEntitiesQuery';
import { executionSortFields } from '../../models/Execution/constants';
import { makeListLaunchPlansQuery } from '../../queries/launchPlanQueries';
import keys from 'lodash/keys';
import { FilterOperationName } from '@clients/common/types/adminEntityTypes';
import classnames from 'classnames';
import { LocalCacheItem, useLocalCache } from '../../basics/LocalCache';
import {
getScheduleFrequencyString,
getScheduleOffsetString,
formatDateUTC,
} from '../../common/formatters';
import { timestampToDate } from '../../common/utils';
import { useCommonStyles } from '../common/styles';
import { ResourceIdentifier, ResourceType } from '../../models/Common/types';
import { FixedRateUnit, ResourceIdentifier } from '../../models/Common/types';
import { LaunchPlan } from '../../models/Launch/types';
import { entityStrings } from './constants';
import t, { patternKey } from './strings';

import { LaunchPlanLastNExecutions } from '../LaunchPlan/components/LaunchPlanLastNExecutions';
import { LaunchPlanNextPotentialExecution } from '../LaunchPlan/components/LaunchPlanNextPotentialExecution';
import { ScheduleDisplayValue, ScheduleStatus } from '../LaunchPlan/components/LaunchPlanCells';
import { useConditionalQuery } from '../hooks/useConditionalQuery';
import { WaitForQuery } from '../common/WaitForQuery';
import { executionFilterGenerator } from './generators';
import { useLatestActiveLaunchPlan } from '../LaunchPlan/hooks/useLatestActiveLaunchPlan';
import {
LaunchPlanLastRun,
LaunchPlanName,
LaunchPlanNextPotentialExecution,
ScheduleFrequency,
} from './EntitySchedulesCells';

const EntitySchedulesContainer = styled('div')(({ theme }) => ({
'.header': {
Expand All @@ -54,131 +47,119 @@ const EntitySchedulesContainer = styled('div')(({ theme }) => ({
},
}));

export const getScheduleStringFromLaunchPlan = (launchPlan: LaunchPlan) => {
const { schedule } = launchPlan.spec.entityMetadata;
const frequencyString = getScheduleFrequencyString(schedule);
const offsetString = getScheduleOffsetString(schedule);
const scheduleString = offsetString
? `${frequencyString} (offset by ${offsetString})`
: frequencyString;
export const getRawScheduleStringFromLaunchPlan = (launchPlan?: LaunchPlan) => {
const { schedule } = launchPlan?.spec?.entityMetadata || {};
if (schedule?.rate) {
const unit = schedule?.rate.unit;
const unitString =
keys(FixedRateUnit).find((key) => (FixedRateUnit[key as any] as any) === unit) || '';

return scheduleString;
return `${schedule?.rate.value}, ${
unitString.charAt(0).toUpperCase() + unitString.slice(1).toLowerCase()
}`;
}
if (schedule?.cronSchedule) {
return schedule.cronSchedule.schedule;
}

return '';
};

const RenderSchedules: React.FC<{
const EntitySchedulesTable: React.FC<{
id: ResourceIdentifier;
launchPlans: LaunchPlan[];
refetch: () => void;
}> = ({ launchPlans, refetch }) => {
return (
}> = ({ id, launchPlans }) => {
const commonStyles = useCommonStyles();
const cellClass = classnames('cell', 'header');

return launchPlans.length > 0 ? (
<Table size="small" sx={{ margin: '10px 0' }}>
<TableHead>
<TableRow>
<TableCell>
<Typography variant="h3">{t(patternKey('launchPlan', 'status'))}</Typography>
</TableCell>
<TableCell>
<Typography variant="h3">{t(patternKey('launchPlan', 'schedule'))}</Typography>
</TableCell>
<TableCell>
<Typography variant="h3">{t(patternKey('launchPlan', 'lastExecution'))}</Typography>
<TableCell
classes={{
root: cellClass,
}}
>
{t(patternKey('launchPlan', 'scheduleFrequency'))}
</TableCell>
<TableCell>
<Typography variant="h3">
{t(patternKey('launchPlan', 'nextPotentialExecution'))}
</Typography>
<TableCell
classes={{
root: cellClass,
}}
>
{t(patternKey('launchPlan', 'name'))}
</TableCell>
<TableCell>
<Typography variant="h3">{t(patternKey('launchPlan', 'createdAt'))}</Typography>
<TableCell
classes={{
root: cellClass,
}}
>
{t(patternKey('launchPlan', 'lastExecution'))}
</TableCell>
<TableCell>
<Typography variant="h3">{t(patternKey('launchPlan', 'scheduledVersion'))}</Typography>
<TableCell
classes={{
root: cellClass,
}}
>
{t(patternKey('launchPlan', 'nextPotentialExecution'))}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{launchPlans.map((launchPlan) => {
const createdAt = launchPlan?.closure?.createdAt!;
const createdAtTime = formatDateUTC(timestampToDate(createdAt));

return (
<TableRow key={launchPlan.id.name}>
<TableCell className="rowCell">
<ScheduleStatus launchPlan={launchPlan} refetch={refetch} />
<ScheduleFrequency launchPlan={launchPlan} />
</TableCell>
<TableCell className="rowCell">
<ScheduleDisplayValue launchPlan={launchPlan} />
<LaunchPlanName launchPlan={launchPlan} />
</TableCell>
<TableCell className="rowCell">
<LaunchPlanLastNExecutions launchPlan={launchPlan} showLastExecutionOnly inView />
<LaunchPlanLastRun launchPlan={launchPlan} />
</TableCell>
<TableCell className="rowCell">
<LaunchPlanNextPotentialExecution launchPlan={launchPlan} />
</TableCell>
<TableCell className="rowCell">{createdAtTime}</TableCell>
<TableCell className="rowCell">{launchPlan.id.version}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
) : (
<Typography variant="body2" className={commonStyles.hintText}>
{t(patternKey('noSchedules', entityStrings[id.resourceType]))}
</Typography>
);
};

const sort = {
key: executionSortFields.createdAt,
direction: SortDirection.DESCENDING,
};
export const EntitySchedules: React.FC<{
id: ResourceIdentifier;
}> = ({ id }) => {
const queryClient = useQueryClient();
const commonStyles = useCommonStyles();
const [showTable, setShowTable] = useLocalCache(LocalCacheItem.ShowLaunchplanSchedules);

const { domain, project } = id || {};

// capture if we are on a launch plan details page page
const isLaunchPlan = id.resourceType === ResourceType.LAUNCH_PLAN;

// if not on a launch plan details page, get the latest version of the entity(workflow)
const workflowEntityDescriptionQuery = useConditionalQuery(
{
enabled: !isLaunchPlan,
...makeListDescriptionEntitiesQuery(queryClient, { ...id, version: '' }, { sort, limit: 1 }),
},
(prev) => !prev && !!showTable,
);

// get the latest version of the workflow
const latestVersionId = workflowEntityDescriptionQuery.data?.entities?.[0]?.id;

// get the filters for the latestVersionId
const filter = latestVersionId
? executionFilterGenerator[latestVersionId.resourceType!](
latestVersionId as any,
latestVersionId?.version,
)
: undefined;

// if the ID is a launchPlan, use the original ID, otherwise use the workflow latest version ID
const launchPlanRequestId = isLaunchPlan ? id : latestVersionId && { domain, project };
const launchPlanQuery = useConditionalQuery(
{
enabled: !!launchPlanRequestId,
...makeListLaunchPlansQuery(queryClient, launchPlanRequestId!, {
sort,
limit: 1,
...(isLaunchPlan ? {} : { filter }),
}),
},
(prev) => !prev && !!showTable,
);
const latestActiveSchedulesQuery = useLatestActiveLaunchPlan({
// Don't pass the wf name here, it's already included in the additionalFilters
id: {
project: id.project,
domain: id.domain,
} as any,
limit: 5,
// add the workflow name to the filter
additionalFilters: [
{
key: 'workflow.name',
operation: FilterOperationName.EQ,
value: id.name,
},
],
});

return (
<WaitForQuery query={launchPlanQuery}>
{(data) => {
const launchPlans = data.entities;
const isSchedulePresent = launchPlans?.[0]?.spec?.entityMetadata?.schedule != null;
<WaitForQuery query={latestActiveSchedulesQuery}>
{({ entities: launchPlans }) => {
const isSchedulePresent = !!launchPlans?.length;
return isSchedulePresent ? (
<EntitySchedulesContainer>
<Grid container item alignSelf="center" justifyContent="space-between">
Expand Down Expand Up @@ -207,13 +188,7 @@ export const EntitySchedules: React.FC<{
</Grid>
{showTable ? (
<div className="schedulesContainer">
{launchPlans.length > 0 ? (
<RenderSchedules launchPlans={launchPlans} refetch={launchPlanQuery.refetch} />
) : (
<Typography variant="body2" className={commonStyles.hintText}>
{t(patternKey('noSchedules', entityStrings[id.resourceType]))}
</Typography>
)}
<EntitySchedulesTable launchPlans={launchPlans} id={id} />
</div>
) : (
<Divider />
Expand Down
Loading

0 comments on commit 88778e2

Please sign in to comment.