Skip to content

Commit

Permalink
[dagit] Add active state to left nav items (#8147)
Browse files Browse the repository at this point in the history
  • Loading branch information
hellendag committed Jun 2, 2022
1 parent 35b5241 commit 6fddda8
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 126 deletions.
208 changes: 103 additions & 105 deletions js_modules/dagit/packages/core/src/nav/FlatContentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface Props {
repoPath?: string;
}

export type JobItemType = {
export type LeftNavItemType = {
name: string;
isJob: boolean;
label: React.ReactNode;
Expand All @@ -48,15 +48,15 @@ export const FlatContentList: React.FC<Props> = (props) => {
}, [repos]);

const jobs = React.useMemo(() => {
const items: JobItemType[] = [];
const items: LeftNavItemType[] = [];

for (const option of repos) {
const {repository, repositoryLocation} = option;
const address = buildRepoAddress(repository.name, repositoryLocation.name);
if (!activeRepoAddresses.has(address)) {
continue;
}
items.push(...getJobItemsForOption(option));
items.push(...getLeftNavItemsForOption(option));
}

return items.sort((a, b) =>
Expand All @@ -76,21 +76,23 @@ export const FlatContentList: React.FC<Props> = (props) => {
<span style={{fontSize: '16px', fontWeight: 600}}>{title}</span>
</Box>
<Items style={{height: 'calc(100% - 226px)'}}>
{jobs.map((job) => (
<JobItem
key={`${job.name}-${repoAddressAsString(job.repoAddress)}`}
job={job}
repoPath={repoPath}
selector={selector}
/>
))}
{jobs.map((job) => {
const repoString = repoAddressAsString(job.repoAddress);
return (
<LeftNavItem
key={`${job.name}-${repoString}`}
job={job}
active={!!(repoPath && repoString === repoPath && selector === job.name)}
/>
);
})}
</Items>
</>
);
};

export const getJobItemsForOption = (option: DagsterRepoOption) => {
const items: JobItemType[] = [];
export const getLeftNavItemsForOption = (option: DagsterRepoOption) => {
const items: LeftNavItemType[] = [];

const {repository, repositoryLocation} = option;
const address = buildRepoAddress(repository.name, repositoryLocation.name);
Expand Down Expand Up @@ -128,116 +130,112 @@ export const getJobItemsForOption = (option: DagsterRepoOption) => {
return items;
};

interface JobItemProps {
job: JobItemType;
repoPath?: string;
selector?: string;
interface LeftNavItemProps {
active: boolean;
job: LeftNavItemType;
}

export const JobItem: React.FC<JobItemProps> = (props) => {
const {job: jobItem, repoPath, selector} = props;
const {name, label, path, repoAddress, schedules, sensors} = jobItem;

const [showDialog, setShowDialog] = React.useState(false);

const jobRepoPath = repoAddressAsString(repoAddress);

const icon = () => {
const scheduleCount = schedules.length;
const sensorCount = sensors.length;
export const LeftNavItem = React.forwardRef(
(props: LeftNavItemProps, ref: React.ForwardedRef<HTMLDivElement>) => {
const {active, job: LeftNavItem} = props;
const {label, path, repoAddress, schedules, sensors} = LeftNavItem;

if (!scheduleCount && !sensorCount) {
return null;
}

const whichIcon = scheduleCount ? 'schedule' : 'sensors';
const needsDialog = scheduleCount > 1 || sensorCount > 1 || (scheduleCount && sensorCount);
const [showDialog, setShowDialog] = React.useState(false);

const status = () => {
return schedules.some(
(schedule) => schedule.scheduleState.status === InstigationStatus.RUNNING,
) || sensors.some((sensor) => sensor.sensorState.status === InstigationStatus.RUNNING)
? InstigationStatus.RUNNING
: InstigationStatus.STOPPED;
};
const icon = () => {
const scheduleCount = schedules.length;
const sensorCount = sensors.length;

const tooltipContent = () => {
if (scheduleCount && sensorCount) {
const scheduleString = scheduleCount > 1 ? `${scheduleCount} schedules` : '1 schedule';
const sensorString = sensorCount > 1 ? `${sensorCount} sensors` : '1 sensor';
return `${scheduleString}, ${sensorString}`;
if (!scheduleCount && !sensorCount) {
return null;
}

if (scheduleCount) {
return scheduleCount === 1 ? (
const whichIcon = scheduleCount ? 'schedule' : 'sensors';
const needsDialog = scheduleCount > 1 || sensorCount > 1 || (scheduleCount && sensorCount);

const status = () => {
return schedules.some(
(schedule) => schedule.scheduleState.status === InstigationStatus.RUNNING,
) || sensors.some((sensor) => sensor.sensorState.status === InstigationStatus.RUNNING)
? InstigationStatus.RUNNING
: InstigationStatus.STOPPED;
};

const tooltipContent = () => {
if (scheduleCount && sensorCount) {
const scheduleString = scheduleCount > 1 ? `${scheduleCount} schedules` : '1 schedule';
const sensorString = sensorCount > 1 ? `${sensorCount} sensors` : '1 sensor';
return `${scheduleString}, ${sensorString}`;
}

if (scheduleCount) {
return scheduleCount === 1 ? (
<div>
Schedule: <strong>{humanCronString(schedules[0].cronSchedule)}</strong>
</div>
) : (
`${scheduleCount} schedules`
);
}

return sensorCount === 1 ? (
<div>
Schedule: <strong>{humanCronString(schedules[0].cronSchedule)}</strong>
Sensor: <strong>{sensors[0].name}</strong>
</div>
) : (
`${scheduleCount} schedules`
`${sensorCount} sensors`
);
}

return sensorCount === 1 ? (
<div>
Sensor: <strong>{sensors[0].name}</strong>
</div>
) : (
`${sensorCount} sensors`
);
};

const link = () => {
const icon = (
<Icon
name={whichIcon}
color={status() === InstigationStatus.RUNNING ? Colors.Green500 : Colors.Gray600}
/>
);
};

if (needsDialog) {
return (
<SensorScheduleDialogButton onClick={() => setShowDialog(true)}>
{icon}
</SensorScheduleDialogButton>
const link = () => {
const icon = (
<Icon
name={whichIcon}
color={status() === InstigationStatus.RUNNING ? Colors.Green500 : Colors.Gray600}
/>
);
}

const path = scheduleCount
? `/schedules/${schedules[0].name}`
: `/sensors/${sensors[0].name}`;
return <Link to={workspacePathFromAddress(repoAddress, path)}>{icon}</Link>;
if (needsDialog) {
return (
<SensorScheduleDialogButton onClick={() => setShowDialog(true)}>
{icon}
</SensorScheduleDialogButton>
);
}

const path = scheduleCount
? `/schedules/${schedules[0].name}`
: `/sensors/${sensors[0].name}`;
return <Link to={workspacePathFromAddress(repoAddress, path)}>{icon}</Link>;
};

return (
<>
<IconWithTooltip content={tooltipContent()}>{link()}</IconWithTooltip>
{needsDialog ? (
<ScheduleAndSensorDialog
isOpen={showDialog}
onClose={() => setShowDialog(false)}
repoAddress={repoAddress}
schedules={schedules}
sensors={sensors}
showSwitch
/>
) : null}
</>
);
};

return (
<>
<IconWithTooltip content={tooltipContent()}>{link()}</IconWithTooltip>
{needsDialog ? (
<ScheduleAndSensorDialog
isOpen={showDialog}
onClose={() => setShowDialog(false)}
repoAddress={repoAddress}
schedules={schedules}
sensors={sensors}
showSwitch
/>
) : null}
</>
<ItemContainer ref={ref}>
<Item $active={active} to={path}>
<div>{label}</div>
</Item>
{icon()}
</ItemContainer>
);
};

return (
<ItemContainer>
<Item
className={`${name === selector && repoPath === jobRepoPath ? 'selected' : ''}`}
to={path}
>
<div>{label}</div>
</Item>
{icon()}
</ItemContainer>
);
};
},
);

const Label = styled.div<{$hasIcon: boolean}>`
display: flex;
Expand Down
12 changes: 5 additions & 7 deletions js_modules/dagit/packages/core/src/nav/RepositoryContentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@ export const Items = styled.div`
}
`;

export const Item = styled(Link)`
export const Item = styled(Link)<{$active: boolean}>`
background-color: ${({$active}) => ($active ? Colors.Blue50 : 'transparent')};
border-radius: 8px;
font-size: 14px;
text-overflow: ellipsis;
overflow: hidden;
padding: 6px 12px;
display: block;
color: ${Colors.Gray900} !important;
color: ${({$active}) => ($active ? Colors.Blue700 : Colors.Dark)} !important;
user-select: none;
transition: background 50ms linear, color 50ms linear;
&:hover {
text-decoration: none;
background-color: ${Colors.Gray10};
background-color: ${({$active}) => ($active ? Colors.Blue50 : Colors.Gray10)};
}
&:focus {
Expand All @@ -45,8 +47,4 @@ export const Item = styled(Link)`
&.focused {
border-left: 4px solid ${Colors.Gray400};
}
&.selected {
background: ${Colors.Gray200};
}
`;

0 comments on commit 6fddda8

Please sign in to comment.