Skip to content

Commit

Permalink
UI basic api (apache#15015)
Browse files Browse the repository at this point in the history
  • Loading branch information
bbovenzi authored Mar 25, 2021
1 parent db9febd commit b1ce429
Show file tree
Hide file tree
Showing 19 changed files with 411 additions and 118 deletions.
2 changes: 1 addition & 1 deletion airflow/ui/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module.exports = {
env: {
jest: true,
},
extends: ['airbnb-typescript'],
extends: ['airbnb-typescript', 'plugin:react-hooks/recommended'],
parserOptions: {
project: './tsconfig.json',
},
Expand Down
2 changes: 2 additions & 0 deletions airflow/ui/.neutrinorc.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ module.exports = {
neutrino.config.resolve.alias.set('utils', resolve(__dirname, 'src/utils'));
neutrino.config.resolve.alias.set('auth', resolve(__dirname, 'src/auth'));
neutrino.config.resolve.alias.set('components', resolve(__dirname, 'src/components'));
neutrino.config.resolve.alias.set('interfaces', resolve(__dirname, 'src/interfaces'));
neutrino.config.resolve.alias.set('api', resolve(__dirname, 'src/api'));
},
typescript(),
// Modify typescript config in .tsconfig.json
Expand Down
1 change: 1 addition & 0 deletions airflow/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- [Neutrino](https://neutrinojs.org/) - lets you build web and Node.js applications with shared presets or configurations.
- [Chakra UI](https://chakra-ui.com/) - a simple, modular and accessible component library that gives you all the building blocks you need to build your React applications.
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) - write tests that focus on functionality instead of implementation
- [React Query](https://react-query.tanstack.com/) - powerful async data handler. all API calls go through this

## Environment variables

Expand Down
8 changes: 8 additions & 0 deletions airflow/ui/docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,18 @@ the more confidence they can give you." Keep their [cheatsheet](https://testing-

- Neutrino handles our App's configuration and Webpack build. Check out their [docs](https://neutrinojs.org/api/) if you need to customize it.

- State management is handled with [Context](https://reactjs.org/docs/context.html) and [react-query](https://react-query.tanstack.com/). Context is used for App-level state that doesn't change often (authentication, dark/light mode). React Query handles all the state and side effects (loading, error, caching, etc) of async data from the API.

## Project Structure

- `src/index.tsx` is the entry point of the app. Here you will find all the root level Providers that expose functionality to the rest of the app like the Chakra component library, routing, authentication or API queries.
- `.neutrinorc.js` is the main config file. Although some custom typescript or linting may need to be changed in `tsconfig.json` or `.eslintrc.js`, respectively
- `src/components` are React components that will be shared across the app
- `src/views` are React components that are specific to a certain url route
- `src/interfaces` are custom-defined Typescript types/interfaces
- `src/utils` contains various helper functions that are shared throughout the app
- `src/auth` has the Context for authentication
- `src/api` contains all of the actual API requests as custom hooks around react-query

## Find open issues

Expand Down
3 changes: 3 additions & 0 deletions airflow/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dayjs": "^1.10.4",
"dotenv": "^8.2.0",
"framer-motion": "^3.10.0",
"humps": "^2.0.1",
"react": "^16",
"react-dom": "^16",
"react-hot-loader": "^4",
Expand All @@ -30,6 +31,7 @@
"@neutrinojs/react": "^9.5.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@types/humps": "^2.0.0",
"@types/jest": "^26.0.20",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.2",
Expand All @@ -38,6 +40,7 @@
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react-hooks": "^4.2.0",
"history": "^5.0.0",
"jest": "^26",
"neutrino": "^9.5.0",
Expand Down
2 changes: 1 addition & 1 deletion airflow/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import Runs from 'views/Activity/Runs';
import Jobs from 'views/Activity/Jobs';
import TaskInstances from 'views/Activity/TaskInstances';
import TaskReschedules from 'views/Activity/TaskReschedules';
import SLAMisses from 'views/Activity/SlaMisses';
import SLAMisses from 'views/Activity/SLAMisses';
import XComs from 'views/Activity/XComs';

import Config from 'views/Config';
Expand Down
22 changes: 22 additions & 0 deletions airflow/ui/src/api/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*!
* 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.
*/

export const defaultVersion = { version: '', gitVersion: '' };

export const defaultDags = { dags: [], totalEntries: 0 };
47 changes: 47 additions & 0 deletions airflow/ui/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*!
* 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 axios, { AxiosResponse } from 'axios';
import { useQuery } from 'react-query';
import humps from 'humps';

import type { Version } from 'interfaces';
import type { DagsResponse } from 'interfaces/api';

axios.defaults.baseURL = `${process.env.WEBSERVER_URL}/api/v1`;
axios.interceptors.response.use(
(res) => (res.data ? humps.camelizeKeys(res.data) as unknown as AxiosResponse : res),
);

const refetchInterval = 1000;

export function useDags() {
return useQuery<DagsResponse, Error>(
'dags',
(): Promise<DagsResponse> => axios.get('/dags'),
{ refetchInterval },
);
}

export function useVersion() {
return useQuery<Version, Error>(
'version',
(): Promise<Version> => axios.get('/version'),
);
}
6 changes: 4 additions & 2 deletions airflow/ui/src/components/AppContainer/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const AppHeader: React.FC<Props> = ({ bodyBg, overlayBg, breadcrumb }) => {
const now = dayjs();
const headerHeight = '56px';
const { hasValidAuthToken, logout } = useAuthContext();
const darkLightIcon = useColorModeValue(MdBrightness2, MdWbSunny);
const darkLightText = useColorModeValue(' Dark ', ' Light ');

const handleOpenTZ = () => window.alert('This will open time zone select modal!');

Expand Down Expand Up @@ -108,9 +110,9 @@ const AppHeader: React.FC<Props> = ({ bodyBg, overlayBg, breadcrumb }) => {
Your Profile
</MenuItem>
<MenuItem onClick={toggleColorMode}>
<Icon as={useColorModeValue(MdBrightness2, MdWbSunny)} mr="2" />
<Icon as={darkLightIcon} mr="2" />
Set
{useColorModeValue(' Dark ', ' Light ')}
{darkLightText}
Mode
</MenuItem>
<MenuDivider />
Expand Down
8 changes: 3 additions & 5 deletions airflow/ui/src/components/AppContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {
useColorModeValue,
} from '@chakra-ui/react';

// import { useVersion } from 'api';
// import { defaultVersion } from 'api/defaults';
import { useVersion } from 'api';
import { defaultVersion } from 'api/defaults';
import AppHeader from './AppHeader';
import AppNav from './AppNav';

Expand All @@ -34,9 +34,7 @@ interface Props {
}

const AppContainer: React.FC<Props> = ({ children, breadcrumb }) => {
// const { data: { version, gitVersion } = defaultVersion } = useVersion();
const version = '2.0.0';
const gitVersion = '';
const { data: { version, gitVersion } = defaultVersion } = useVersion();
const bodyBg = useColorModeValue('white', 'gray.800');
const overlayBg = useColorModeValue('gray.100', 'gray.700');

Expand Down
76 changes: 41 additions & 35 deletions airflow/ui/src/components/SectionWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,41 +40,46 @@ interface Props {

const SectionWrapper: React.FC<Props> = ({
children, currentSection, currentView, navItems, toolBar,
}) => (
<AppContainer
breadcrumb={(
<Heading as="h1" size="md">
<Box
as="span"
color={useColorModeValue('gray.400', 'gray.500')}
>
{currentSection}
/
</Box>
{currentView}
</Heading>
}) => {
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 (
<AppContainer
breadcrumb={(
<Heading as="h1" size="md">
<Box
as="span"
color={heading}
>
{currentSection}
/
</Box>
{currentView}
</Heading>
)}
>
<Box
pt={2}
mx={-4}
px={4}
pb="2"
bg={useColorModeValue('gray.100', 'gray.700')}
>
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
pt={2}
mx={-4}
px={4}
pb="2"
bg={bg}
>
<Box as="nav">
{navItems.map((item) => (
<SectionNavBtn key={item.label} item={item} currentLabel={currentView} />
))}
<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>
</Box>
{toolBar && (
{toolBar && (
<Box
position="sticky"
top="0"
Expand All @@ -87,14 +92,15 @@ const SectionWrapper: React.FC<Props> = ({
py={2}
px={4}
borderBottomWidth="2px"
borderBottomColor={useColorModeValue('gray.100', 'gray.700')}
backgroundColor={useColorModeValue('white', 'gray.800')}
borderBottomColor={border}
backgroundColor={toolbarBg}
>
{toolBar}
</Box>
)}
<Box py="4">{children}</Box>
</AppContainer>
);
)}
<Box py="4">{children}</Box>
</AppContainer>
);
};

export default SectionWrapper;
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,12 @@
* under the License.
*/

import React from 'react';
import { Center, Heading } from '@chakra-ui/react';
import AppContainer from 'components/AppContainer';
import type { Dag } from './index';

const Pipelines: React.FC = () => (
<AppContainer>
<Center height="100%" width="100%">
<Heading>Pipelines</Heading>
</Center>
</AppContainer>
);
interface Entries {
totalEntries: number;
}

export default Pipelines;
export interface DagsResponse extends Entries {
dags: Dag[];
}
52 changes: 52 additions & 0 deletions airflow/ui/src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*!
* 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.
*/

export interface DagTag {
name: string,
}

export interface TimeDelta {
days: number,
microseconds: number,
seconds: number,
type: string,
}

export interface CronExpression {
type: string,
value: string,
}

export interface Dag {
dagId: string,
rootDagId: string,
isPaused: boolean,
isSubdag: boolean,
fileloc: string,
fileToken: string,
owners: Array<string>,
description: string,
scheduleInterval?: TimeDelta | CronExpression,
tags: DagTag[],
}

export interface Version {
version: string,
gitVersion: string,
}
Loading

0 comments on commit b1ce429

Please sign in to comment.