정민우

Merge branch 'frontend' into 'master'

[New] Docker Image 관련 화면 추가, Navigation 추가 등



See merge request !10
1 -import React, { useEffect } from 'react' 1 +import React, { useEffect, useState } from 'react'
2 import { BrowserRouter, Route, Redirect, Switch, Link } from 'react-router-dom' 2 import { BrowserRouter, Route, Redirect, Switch, Link } from 'react-router-dom'
3 import { ChakraProvider } from '@chakra-ui/react' 3 import { ChakraProvider } from '@chakra-ui/react'
4 +import Navigation from './components/Navigation'
4 import Index from './components/Index' 5 import Index from './components/Index'
5 import SignIn from './components/SignIn' 6 import SignIn from './components/SignIn'
6 import SignUp from './components/SignUp' 7 import SignUp from './components/SignUp'
8 +import DockerImageCreate from './components/DockerImageCreate'
9 +import DockerImageList from './components/DockerImageList'
7 import DockerContainerCreate from './components/DockerContainerCreate' 10 import DockerContainerCreate from './components/DockerContainerCreate'
8 import DockerContainerList from './components/DockerContainerList' 11 import DockerContainerList from './components/DockerContainerList'
9 import 'semantic-ui-css/semantic.min.css' 12 import 'semantic-ui-css/semantic.min.css'
...@@ -12,12 +15,17 @@ const App = () => { ...@@ -12,12 +15,17 @@ const App = () => {
12 return ( 15 return (
13 <ChakraProvider> 16 <ChakraProvider>
14 <BrowserRouter> 17 <BrowserRouter>
18 + <Navigation/>
15 <Switch> 19 <Switch>
16 <Route exact path="/" component={Index}/> 20 <Route exact path="/" component={Index}/>
17 <Route exact path="/sign-in" component={SignIn}/> 21 <Route exact path="/sign-in" component={SignIn}/>
18 <Route exact path="/sign-up" component={SignUp}/> 22 <Route exact path="/sign-up" component={SignUp}/>
19 - <Route exact path="/docker/container/create" component={DockerContainerCreate}/> 23 + <Route exact path="/docker/image/create" component={DockerImageCreate}/>
20 - <Route exact path="/docker/container/list" component={DockerContainerList}/> 24 + <Route exact path="/docker/image/list" component={DockerImageList}/>
25 + <Route exact path="/docker/container/create"
26 + component={DockerContainerCreate}/>
27 + <Route exact path="/docker/container/list"
28 + component={DockerContainerList}/>
21 <Redirect path="*" to="/"/> 29 <Redirect path="*" to="/"/>
22 </Switch> 30 </Switch>
23 </BrowserRouter> 31 </BrowserRouter>
......
...@@ -63,37 +63,6 @@ const DockerContainerList = () => { ...@@ -63,37 +63,6 @@ const DockerContainerList = () => {
63 </ListItem> 63 </ListItem>
64 ))} 64 ))}
65 </UnorderedList> 65 </UnorderedList>
66 -
67 - <Stack
68 - divider={<StackDivider borderColor="gray.200"/>}
69 - spacing={4}
70 - align="stretch"
71 - >
72 -
73 -
74 - <FormControl id="container" isRequired>
75 - <FormLabel>Container Name</FormLabel>
76 - <Input
77 - type="email"
78 - placeholder="Container Name"
79 - />
80 - </FormControl>
81 -
82 - <FormControl id="image">
83 - <FormLabel>Image</FormLabel>
84 - <Select placeholder="생성할 컨테이너의 OS를 설정해주세요">
85 - <option value="ubuntu 18.04">Ubuntu 18.04.5 LTS</option>
86 - <option value="ubuntu 20.04">Ubuntu 20.04.2 LTS</option>
87 - </Select>
88 - </FormControl>
89 -
90 - </Stack>
91 -
92 - <Stack>
93 -
94 - </Stack>
95 -
96 -
97 </Container> 66 </Container>
98 ) 67 )
99 } 68 }
......
1 +import React, { useEffect, useState } from 'react'
2 +import {
3 + Container,
4 + Heading,
5 + Button,
6 + Text,
7 + Box, Alert, AlertIcon,
8 + AlertDialog,
9 + AlertDialogContent,
10 + AlertDialogOverlay,
11 +} from '@chakra-ui/react'
12 +import {
13 + Divider,
14 + TextArea,
15 + Header,
16 + Grid,
17 + Form,
18 +} from 'semantic-ui-react'
19 +import http from '../utils/http'
20 +import { useHistory } from 'react-router-dom'
21 +
22 +
23 +const DockerImageCreate = () => {
24 + const [token, setToken] = useState('')
25 + const [dockerfile, setDockerfile] = useState('')
26 + const [isSuccess, setSuccess] = useState(false)
27 +
28 + const history = useHistory()
29 +
30 + const uploadDockerfile = () => {
31 + http.post('/dockerfile/add', {
32 + content: dockerfile,
33 + }, {
34 + headers: {
35 + Authorization: `token ${token}`,
36 + }
37 + }).then(response => {
38 + const {success, data, message} = response.data
39 + if (success) {
40 + setSuccess(success)
41 + setTimeout(2000, () => {
42 + history.push('/docker/image/list')
43 + })
44 + }
45 + })
46 + }
47 +
48 + useEffect(() => {
49 + const token = localStorage.getItem('token')
50 + setToken(token)
51 + }, [])
52 +
53 + return (
54 + <Container>
55 + <Divider hidden/>
56 + <Heading>Upload Your Dockerfile</Heading>
57 +
58 + <Divider hidden />
59 +
60 + <Form>
61 + <span>dockerfile : </span>
62 + <TextArea
63 + value={dockerfile}
64 + rows={dockerfile.split('\n').length + 2}
65 + onChange={(e, {value}) => setDockerfile(value)}
66 + />
67 + </Form>
68 + <Divider hidden/>
69 + <Grid>
70 + <Grid.Column
71 + width={3}
72 + floated='right'
73 + >
74 + <Button
75 + size='sm'
76 + colorScheme='teal'
77 + onClick={() => uploadDockerfile()}
78 + >
79 + Upload
80 + </Button>
81 + </Grid.Column>
82 + </Grid>
83 +
84 +
85 + <AlertDialog
86 + isOpen={isSuccess}
87 + onClose={() => setSuccess(false)}
88 + >
89 + <AlertDialogOverlay>
90 + <AlertDialogContent>
91 + <Alert status="success">
92 + <AlertIcon />
93 + Successfully uploaded !
94 + </Alert>
95 + </AlertDialogContent>
96 + </AlertDialogOverlay>
97 + </AlertDialog>
98 +
99 + </Container>
100 + )
101 +}
102 +
103 +export default DockerImageCreate
1 +import React, { useEffect, useState } from 'react'
2 +import {
3 + Container,
4 + Heading,
5 + Button,
6 + Text,
7 + Box,
8 +} from '@chakra-ui/react'
9 +import {
10 + Divider, Grid,
11 + Header,
12 +} from 'semantic-ui-react'
13 +import http from '../utils/http'
14 +import { useHistory } from 'react-router-dom'
15 +
16 +const ImageBlock = ({ title, desc, ...rest }) => {
17 + return (
18 + <Box p={5} shadow="md" borderWidth="1px" {...rest}>
19 + <Heading fontSize="xl">{title}</Heading>
20 + <Text mt={4}>{desc}</Text>
21 + </Box>
22 + )
23 +}
24 +
25 +const DockerImageList = () => {
26 + const [token, setToken] = useState('')
27 + const [images, setImages] = useState([])
28 +
29 + const history = useHistory()
30 +
31 + const setTokenFromLocalStorage = () => {
32 + const token = localStorage.getItem('token')
33 + setToken(token)
34 + }
35 +
36 + const getImages = () => {
37 + http.get('/image/list', {
38 + headers: {
39 + Authorization: `token ${token}`,
40 + },
41 + }).then(response => {
42 + const { success, code, data, message } = response.data
43 + if (success) {
44 + const { count, data } = data
45 + setImages(data)
46 + }
47 + })
48 + }
49 +
50 + useEffect(() => {
51 + setTokenFromLocalStorage()
52 + getImages()
53 + }, [])
54 +
55 + return (
56 + <Container>
57 + <Divider hidden />
58 + <Heading>Image List</Heading>
59 + <Divider hidden />
60 + <Grid>
61 + <Grid.Column
62 + floated='right' width={3}
63 + >
64 + <Button
65 + size='xs'
66 + colorScheme='blue'
67 + onClick={() => history.push('/docker/image/create')}
68 + >
69 + New Image
70 + </Button>
71 + </Grid.Column>
72 + </Grid>
73 + {images.map(image => (
74 + <ImageBlock
75 + title={image.name}
76 + desc={image.name}
77 + />
78 + ))}
79 + </Container>
80 + )
81 +}
82 +
83 +export default DockerImageList
...\ No newline at end of file ...\ No newline at end of file
1 -import React, { useEffect } from 'react' 1 +import React, { useEffect, useState } from 'react'
2 -import { BrowserRouter, Route, Redirect, Switch, Link, useHistory } from 'react-router-dom' 2 +import {
3 + BrowserRouter,
4 + Route,
5 + Redirect,
6 + Switch,
7 + Link,
8 + useHistory,
9 +} from 'react-router-dom'
3 import { 10 import {
4 Container, 11 Container,
5 Heading, 12 Heading,
...@@ -34,9 +41,10 @@ import { ...@@ -34,9 +41,10 @@ import {
34 Wrap, 41 Wrap,
35 } from '@chakra-ui/react' 42 } from '@chakra-ui/react'
36 import { 43 import {
44 + Tab,
37 Divider, 45 Divider,
38 } from 'semantic-ui-react' 46 } from 'semantic-ui-react'
39 - 47 +import http from '../utils/http'
40 48
41 const Feature = ({ title, desc, ...rest }) => { 49 const Feature = ({ title, desc, ...rest }) => {
42 return ( 50 return (
...@@ -47,59 +55,107 @@ const Feature = ({ title, desc, ...rest }) => { ...@@ -47,59 +55,107 @@ const Feature = ({ title, desc, ...rest }) => {
47 ) 55 )
48 } 56 }
49 57
50 -
51 const Index = () => { 58 const Index = () => {
59 + const [token, setToken] = useState('')
60 + const [currentTab, setCurrentTab] = useState('')
61 + const [me, setMe] = useState({})
62 +
52 const history = useHistory() 63 const history = useHistory()
53 64
65 + const panes = [
66 + {
67 + menuItem: 'Tab 1',
68 + render: () => <Tab.Pane attached={false}>Tab 1 Content</Tab.Pane>,
69 + },
70 + {
71 + menuItem: 'Tab 2',
72 + render: () => <Tab.Pane attached={false}>Tab 2 Content</Tab.Pane>,
73 + },
74 + {
75 + menuItem: 'Tab 3',
76 + render: () => <Tab.Pane attached={false}>Tab 3 Content</Tab.Pane>,
77 + },
78 + ]
79 +
80 + const whoAmI = () => {
81 + http.get('/info/user', {
82 + headers: {
83 + Authorization: `token ${token}`,
84 + },
85 + }).then(response => {
86 + const { success, code, data, message } = response.data
87 + if (success) {
88 + setMe(data)
89 + }
90 + })
91 + }
92 +
93 + useEffect(() => {
94 + const token = localStorage.getItem('token')
95 + setToken(token)
96 +
97 + if (token) {
98 + whoAmI()
99 + }
100 + })
101 +
54 return ( 102 return (
55 <Container> 103 <Container>
56 - <Divider hidden /> 104 + <Divider hidden/>
105 +
106 + {me.name ? (
107 + <Heading size="md">
108 + Hi {me.name}
109 + </Heading>
110 + ) : (
57 <Wrap justify="right"> 111 <Wrap justify="right">
58 <Button size="xs" colorScheme="blue" variant="outline" 112 <Button size="xs" colorScheme="blue" variant="outline"
59 - onClick={() => history.push('/sign-in') } 113 + onClick={() => history.push('/sign-in')}
60 > 114 >
61 SIGN IN 115 SIGN IN
62 </Button> 116 </Button>
63 <Button size="xs" colorScheme="blue" 117 <Button size="xs" colorScheme="blue"
64 - onClick={() => history.push('/sign-up') } 118 + onClick={() => history.push('/sign-up')}
65 > 119 >
66 SIGN UP 120 SIGN UP
67 </Button> 121 </Button>
68 </Wrap> 122 </Wrap>
123 + )}
69 124
70 <Heading>The Infrastructure Cloud</Heading> 125 <Heading>The Infrastructure Cloud</Heading>
71 - <Text>Easily deploy cloud servers, bare metal, and storage worldwide!</Text> 126 + <Text>Easily deploy cloud servers, bare metal, and storage
127 + worldwide!</Text>
72 128
73 - <Divider hidden /> 129 + <Divider hidden/>
74 130
75 131
76 <Stack spacing={8}> 132 <Stack spacing={8}>
77 <Feature 133 <Feature
78 - title='Cloud Compute' 134 + title="Cloud Compute"
79 - desc='Powerful compute instances with Intel CPUs and 100% SSD storage.' 135 + desc="Powerful compute instances with Intel CPUs and 100% SSD storage."
80 /> 136 />
81 137
82 <Feature 138 <Feature
83 - title='Bare Metal' 139 + title="Bare Metal"
84 - desc='Fully automated dedicated servers with zero virtualization layer.' 140 + desc="Fully automated dedicated servers with zero virtualization layer."
85 /> 141 />
86 - </Stack > 142 + </Stack>
87 143
88 - <Divider hidden /> 144 + <Divider hidden/>
89 145
90 <Stack spacing={8}> 146 <Stack spacing={8}>
91 <Feature 147 <Feature
92 - title='Block Storage' 148 + title="Block Storage"
93 - desc='Fast SSD-backed scalable and redundant storage with up to 10TB volumes.' 149 + desc="Fast SSD-backed scalable and redundant storage with up to 10TB volumes."
94 /> 150 />
95 151
96 <Feature 152 <Feature
97 - title='Dedicated Cloud' 153 + title="Dedicated Cloud"
98 - desc='Dedicated cloud compute instances without the noisy neighbors.' 154 + desc="Dedicated cloud compute instances without the noisy neighbors."
99 /> 155 />
100 - </Stack > 156 + </Stack>
101 157
102 - <Divider hidden /> 158 + <Divider hidden/>
103 </Container> 159 </Container>
104 ) 160 )
105 } 161 }
......
1 +import {
2 + Container,
3 +} from '@chakra-ui/react'
4 +import {
5 + Tab,
6 + Divider,
7 +} from 'semantic-ui-react'
8 +import React, { useState } from 'react'
9 +import { Redirect } from 'react-router-dom'
10 +
11 +const Navigation = () => {
12 + const [activeIndex, setActiveIndex] = useState(0)
13 +
14 + const panes = [
15 + {
16 + menuItem: 'Home',
17 + render: () => <Redirect to="/"/>,
18 + },
19 + {
20 + menuItem: 'Image',
21 + render: () => <Redirect to="/docker/image/list"/>,
22 + },
23 + {
24 + menuItem: 'Container',
25 + render: () => <Redirect to="/docker/container/list"/>,
26 + },
27 + ]
28 +
29 + return (
30 + <Container>
31 + <Divider hidden/>
32 + <Tab
33 + panes={panes}
34 + menu={{ secondary: true, pointing: true }}
35 + onTabChange={(e, { activeIndex }) => setActiveIndex(activeIndex)}
36 + />
37 + </Container>
38 + )
39 +}
40 +
41 +export default Navigation