Skip to content

Commit

Permalink
UI scaffold views, routes, and layout containers for Runs and Tasks (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanahamilton authored Mar 26, 2021
1 parent a162f2b commit a7f2cc2
Show file tree
Hide file tree
Showing 28 changed files with 951 additions and 38 deletions.
3 changes: 2 additions & 1 deletion airflow/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"react-hot-loader": "^4",
"react-icons": "^4.2.0",
"react-query": "^3.12.3",
"react-router-dom": "^5.2.0"
"react-router-dom": "^5.2.0",
"use-react-router": "^1.0.7"
},
"devDependencies": {
"@neutrinojs/eslint": "^9.5.0",
Expand Down
35 changes: 33 additions & 2 deletions airflow/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,21 @@ import { Route, Redirect, Switch } from 'react-router-dom';
import PrivateRoute from 'auth/PrivateRoute';

import Pipelines from 'views/Pipelines';
import Pipeline from 'views/Pipeline';

import Details from 'views/Pipeline/runs/Details';
import Code from 'views/Pipeline/runs/Code';
import TaskTries from 'views/Pipeline/runs/TaskTries';
import TaskDuration from 'views/Pipeline/runs/TaskDuration';
import LandingTimes from 'views/Pipeline/runs/LandingTimes';

import Graph from 'views/Pipeline/run/Graph';
import Gantt from 'views/Pipeline/run/Gantt';

import TIDetails from 'views/Pipeline/ti/Details';
import RenderedTemplate from 'views/Pipeline/ti/RenderedTemplate';
import RenderedK8s from 'views/Pipeline/ti/RenderedK8s';
import Log from 'views/Pipeline/ti/Log';
import XCom from 'views/Pipeline/ti/XCom';

import EventLogs from 'views/Activity/EventLogs';
import Runs from 'views/Activity/Runs';
Expand All @@ -51,7 +65,24 @@ const App = () => (
<Switch>
<Redirect exact path="/" to="/pipelines" />
<PrivateRoute exact path="/pipelines" component={Pipelines} />
<PrivateRoute exact path="/pipelines/:dagId" component={Pipeline} />

<Redirect exact path="/pipelines/:dagId" to="/pipelines/:dagId/details" />
<PrivateRoute exact path="/pipelines/:dagId/details" component={Details} />
<PrivateRoute exact path="/pipelines/:dagId/code" component={Code} />
<PrivateRoute exact path="/pipelines/:dagId/task-tries" component={TaskTries} />
<PrivateRoute exact path="/pipelines/:dagId/task-duration" component={TaskDuration} />
<PrivateRoute exact path="/pipelines/:dagId/landing-times" component={LandingTimes} />

<Redirect exact path="/pipelines/:dagId/:dagRunId" to="/pipelines/:dagId/:dagRunId/graph" />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/graph" component={Graph} />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/gantt" component={Gantt} />

<Redirect exact path="/pipelines/:dagId/:dagRunId/:taskId" to="/pipelines/:dagId/:dagRunId/:taskId/details" />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/:taskId/details" component={TIDetails} />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/:taskId/rendered-template" component={RenderedTemplate} />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/:taskId/rendered-k8s" component={RenderedK8s} />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/:taskId/log" component={Log} />
<PrivateRoute exact path="/pipelines/:dagId/:dagRunId/:taskId/xcom" component={XCom} />

<PrivateRoute exact path="/activity/event-logs" component={EventLogs} />
<PrivateRoute exact path="/activity/runs" component={Runs} />
Expand Down
4 changes: 4 additions & 0 deletions airflow/ui/src/api/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@
export const defaultVersion = { version: '', gitVersion: '' };

export const defaultDags = { dags: [], totalEntries: 0 };

export const defaultDagRuns = { dagRuns: [], totalEntries: 0 };

export const defaultTaskInstances = { taskInstances: [], totalEntries: 0 };
21 changes: 19 additions & 2 deletions airflow/ui/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import axios, { AxiosResponse } from 'axios';
import { useQuery } from 'react-query';
import humps from 'humps';

import type { Version } from 'interfaces';
import type { DagsResponse } from 'interfaces/api';
import type { Dag, DagRun, Version } from 'interfaces';
import type { DagsResponse, DagRunsResponse, TaskInstancesResponse } from 'interfaces/api';

axios.defaults.baseURL = `${process.env.WEBSERVER_URL}/api/v1`;
axios.interceptors.response.use(
Expand All @@ -39,6 +39,23 @@ export function useDags() {
);
}

export function useDagRuns(dagId: Dag['dagId'], dateMin?: string) {
return useQuery<DagRunsResponse, Error>(
['dagRun', dagId],
(): Promise<DagRunsResponse> => axios.get(`dags/${dagId}/dagRuns${dateMin ? `?start_date_gte=${dateMin}` : ''}`),
{ refetchInterval },
);
}

export function useTaskInstances(dagId: Dag['dagId'], dagRunId: DagRun['dagRunId'], dateMin?: string) {
return useQuery<TaskInstancesResponse, Error>(
['taskInstance', dagRunId],
(): Promise<TaskInstancesResponse> => (
axios.get(`dags/${dagId}/dagRuns/${dagRunId}/taskInstances${dateMin ? `?start_date_gte=${dateMin}` : ''}`)
),
);
}

export function useVersion() {
return useQuery<Version, Error>(
'version',
Expand Down
93 changes: 93 additions & 0 deletions airflow/ui/src/components/PipelineBreadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import { Link } from 'react-router-dom';
import {
Box, Flex, Heading, useColorModeValue,
} from '@chakra-ui/react';

import type {
Dag as DagType,
DagRun as DagRunType,
Task as TaskType,
} from 'interfaces';

interface Props {
dagId: DagType['dagId'];
dagRunId?: DagRunType['dagRunId'];
taskId?: TaskType['taskId'];
}

const PipelineBreadcrumb: React.FC<Props> = ({ dagId, dagRunId, taskId }) => {
const dividerColor = useColorModeValue('gray.100', 'gray.700');

return (
<Flex py={2}>
<Box>
<Heading as="h5" size="xs" color="gray.500">PIPELINE</Heading>
<Heading as="h4" size="sm">
{!dagRunId && dagId}
{dagRunId && (
<Box
as={Link}
to={`/pipelines/${dagId}`}
color="currentColor"
_hover={{ color: 'teal.500' }}
>
{dagId}
</Box>
)}
</Heading>
</Box>
{dagRunId && (
<>
<Box color={dividerColor} px={2} fontSize="2em" lineHeight="1em">/</Box>
<Box>
<Heading as="h5" size="xs" color="gray.500">RUN</Heading>
<Heading as="h4" size="sm">
{!taskId && dagRunId}
{taskId && (
<Box
as={Link}
to={`/pipelines/${dagId}/${dagRunId}`}
color="currentColor"
_hover={{ color: 'teal.500' }}
>
{dagRunId}
</Box>
)}
</Heading>
</Box>
</>
)}
{taskId && (
<>
<Box color={dividerColor} px={2} fontSize="2em" lineHeight="1em">/</Box>
<Box>
<Heading as="h5" size="xs" color="gray.500">TASK INSTANCE</Heading>
<Heading as="h4" size="sm">{taskId}</Heading>
</Box>
</>
)}
</Flex>
);
};

export default PipelineBreadcrumb;
61 changes: 61 additions & 0 deletions airflow/ui/src/components/SectionNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import {
Box,
useColorModeValue,
} from '@chakra-ui/react';

import SectionNavBtn from 'components/SectionNavBtn';

interface Props {
currentView: string;
navItems: {
label: string;
path: string;
}[]
}

const SectionNav: React.FC<Props> = ({ currentView, navItems }) => {
const bg = useColorModeValue('gray.100', 'gray.700');
return (
<Box
pt={2}
mx={-4}
px={4}
pb={2}
bg={bg}
>
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Box as="nav">
{navItems.map((item) => (
<SectionNavBtn key={item.label} item={item} currentView={currentView} />
))}
</Box>
</Box>
</Box>
);
};

export default SectionNav;
6 changes: 3 additions & 3 deletions airflow/ui/src/components/SectionNavBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ interface Props {
label: string;
path: string;
};
currentLabel: string;
currentView: string;
}

const SectionNavBtn: React.FC<Props> = ({ item, currentLabel }) => {
const SectionNavBtn: React.FC<Props> = ({ item, currentView }) => {
const { label, path } = item;
return (
<Button
as={Link}
to={path}
variant={currentLabel === label ? 'solid' : 'ghost'}
variant={currentView === label ? 'solid' : 'ghost'}
colorScheme="blue"
size="sm"
mr="2"
Expand Down
24 changes: 2 additions & 22 deletions airflow/ui/src/components/SectionWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ import {
useColorModeValue,
} from '@chakra-ui/react';

import SectionNavBtn from 'components/SectionNavBtn';

import AppContainer from 'components/AppContainer';
import SectionNav from 'components/SectionNav';

interface Props {
currentSection: string;
Expand All @@ -42,7 +41,6 @@ const SectionWrapper: React.FC<Props> = ({
children, currentSection, currentView, navItems, toolBar,
}) => {
const heading = useColorModeValue('gray.400', 'gray.500');
const bg = useColorModeValue('gray.100', 'gray.700');
const border = useColorModeValue('gray.100', 'gray.700');
const toolbarBg = useColorModeValue('white', 'gray.800');
return (
Expand All @@ -60,25 +58,7 @@ const SectionWrapper: React.FC<Props> = ({
</Heading>
)}
>
<Box
pt={2}
mx={-4}
px={4}
pb="2"
bg={bg}
>
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Box as="nav">
{navItems.map((item) => (
<SectionNavBtn key={item.label} item={item} currentLabel={currentView} />
))}
</Box>
</Box>
</Box>
<SectionNav navItems={navItems} currentView={currentView} />
{toolBar && (
<Box
position="sticky"
Expand Down
10 changes: 9 additions & 1 deletion airflow/ui/src/interfaces/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import type { Dag } from './index';
import type { Dag, DagRun, TaskInstance } from './index';

interface Entries {
totalEntries: number;
Expand All @@ -26,3 +26,11 @@ interface Entries {
export interface DagsResponse extends Entries {
dags: Dag[];
}

export interface DagRunsResponse extends Entries {
dagRuns: DagRun[];
}

export interface TaskInstancesResponse extends Entries {
taskInstances: TaskInstance[];
}
Loading

0 comments on commit a7f2cc2

Please sign in to comment.