Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
chore: adding more pages to the UI
Browse files Browse the repository at this point in the history
  • Loading branch information
chirino committed Jun 1, 2020
1 parent 0858fcf commit 60abf48
Show file tree
Hide file tree
Showing 16 changed files with 499 additions and 25 deletions.
95 changes: 95 additions & 0 deletions internal/gateway/admin/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package admin

import (
"io/ioutil"
"net/http"

"github.com/chirino/graphql-gw/internal/cmd/config"
ghodssyaml "github.com/ghodss/yaml"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/render"
"gopkg.in/yaml.v2"
)

func CreateHttpHandler() http.Handler {
admin := admin{}
r := chi.NewRouter()

r.Use(middleware.Recoverer)
r.Use(render.SetContentType(render.ContentTypeJSON))

r.Route("/config", func(r chi.Router) {
r.Get("/", admin.GetConfig)
r.Post("/", admin.UpdateConfig)
})

return r
}

type admin struct {
configFile string
}

func (h *admin) UpdateConfig(w http.ResponseWriter, r *http.Request) {

// JSON -> YAML first...
dom := map[string]interface{}{}
err := render.DecodeJSON(r.Body, &dom)
if err != nil {
render.Render(w, r, RenderErr(err, http.StatusBadRequest, "Bad Request"))
return
}
data, err := yaml.Marshal(dom)
if err != nil {
render.Render(w, r, RenderErr(err, http.StatusBadRequest, "Bad Request"))
return
}

// data is now in YAML format... now check it decodes into the Config struct...
c := config.Config{}
err = yaml.Unmarshal(data, &c)
if err != nil {
render.Render(w, r, RenderErr(err, http.StatusBadRequest, "Bad Request"))
return
}
err = config.Store(c)
if err != nil {
render.Render(w, r, RenderErr(err, http.StatusInternalServerError, "Internal Server Error"))
return
}
render.NoContent(w, r)
}

func (h *admin) GetConfig(w http.ResponseWriter, r *http.Request) {
// YAML to JSON conversion...
data, err := ioutil.ReadFile(config.File)
dom := map[string]interface{}{}
err = ghodssyaml.Unmarshal(data, &dom)
if err != nil {
render.Render(w, r, RenderErr(err, http.StatusInternalServerError, "Internal Server Error"))
return
}
render.JSON(w, r, dom)
}

func RenderErr(err error, code int, status string) render.Renderer {
return &ErrResponse{
Err: err,
HTTPStatusCode: code,
StatusText: status,
ErrorText: err.Error(),
}
}

type ErrResponse struct {
Err error `json:"-"` // low-level runtime error
HTTPStatusCode int `json:"-"` // http response status code
StatusText string `json:"status"` // user-level status message
ErrorText string `json:"error,omitempty"` // application-level error message, for debugging
}

func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error {
render.Status(r, e.HTTPStatusCode)
return nil
}
1 change: 1 addition & 0 deletions ui/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GENERATE_SOURCEMAP=true
9 changes: 4 additions & 5 deletions ui/src/App/AppRoutes.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Alert, PageSection } from '@patternfly/react-core';
import * as React from 'react';
import { Route, Switch } from 'react-router-dom';
import { LastLocationProvider, useLastLocation } from 'react-router-last-location';
import {Route, Switch} from 'react-router-dom';
import {LastLocationProvider, useLastLocation} from 'react-router-last-location';

import { NotFound } from '../pages/NotFound';
import {NotFound} from '../pages/NotFound';
import routes from '../routes';
import { accessibleRouteChangeHandler, useDocumentTitle } from '../utils';
import {accessibleRouteChangeHandler, useDocumentTitle} from '../utils';

// const getSupportModuleAsync = () => () => import(/* webpackChunkName: 'support' */ '@app/Support/Support');
// const Support = (routeProps) => {
Expand Down
12 changes: 5 additions & 7 deletions ui/src/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ import './index.css';
import '@patternfly/react-core/dist/styles/base.css';

import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import {BrowserRouter as Router} from 'react-router-dom';

import AppLayout from './AppLayout';
import AppRoutes from './AppRoutes';

export default () => {
return (
<Router>
export default () => (
<Router>
<AppLayout>
<AppRoutes />
<AppRoutes/>
</AppLayout>
</Router>
);
};
)
46 changes: 46 additions & 0 deletions ui/src/components/HasDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {Drawer, DrawerContent, DrawerContentBody} from '@patternfly/react-core';
import React from 'react';


export function useMasterDetailState(setDetails, details, detailsComponentName, propsFn) {
const [selected, setSelected] = React.useState(null);
const onClose = () => {
setSelected(null)
setDetails(null)
}

const onSelect = (id) => {
setSelected(id)
setDetails({
component: detailsComponentName,
props: {onClose: onClose, ...propsFn(id)}
})
}
React.useEffect(() => {
if (details == null || details.component == detailsComponentName) {
setSelected(null)
}
}, [details]);
return {selected, onSelect};
}

const HasDetails = ({children, details, components}) => {

let panelContent = <div></div>;


if (details != null) {
const {component, props = {}} = details
const Component = components[component]
panelContent = <Component {...props}></Component>
}

return (
<Drawer isExpanded={details != null}>
<DrawerContent panelContent={panelContent} className={'pf-m-no-background'}>
<DrawerContentBody hasPadding>{children}</DrawerContentBody>
</DrawerContent>
</Drawer>
)
};
export default HasDetails
2 changes: 1 addition & 1 deletion ui/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';
import App from './App/index';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
Expand Down
35 changes: 35 additions & 0 deletions ui/src/pages/Schema/ActionDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
DrawerActions,
DrawerCloseButton,
DrawerHead,
DrawerPanelBody,
DrawerPanelContent,
Flex,
FlexItem,
FlexModifiers,
Title
} from '@patternfly/react-core';

import React from 'react';

const ActionDetails = ({onClose}) => {

return (<DrawerPanelContent>
<DrawerHead>
<Title headingLevel="h2" size="xl">Action Details</Title>
<DrawerActions>
<DrawerCloseButton onClick={onClose}/>
</DrawerActions>
</DrawerHead>
<DrawerPanelBody>
<Flex breakpointMods={[{modifier: FlexModifiers["space-items-lg"]}, {modifier: FlexModifiers["column"]}]}>
<FlexItem>
<p>The content of the drawer really is up to you. It could have form fields, definition lists, text lists,
labels, charts, progress bars, etc. Spacing recommendation is 24px margins. You can put tabs in here,
and can also make the drawer scrollable.</p>
</FlexItem>
</Flex>
</DrawerPanelBody>
</DrawerPanelContent>)
};
export default ActionDetails
56 changes: 56 additions & 0 deletions ui/src/pages/Schema/ActionList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
Button,
DataList,
DataListCell,
DataListItem,
DataListItemCells,
DataListItemRow,
DataToolbar,
DataToolbarContent,
DataToolbarItem,
Flex,
FlexItem,
FlexModifiers
} from '@patternfly/react-core';

import React from 'react';
import {useMasterDetailState} from "../../components/HasDetails";

const ActionList = ({setDetails, details}) => {

const {selected, onSelect} = useMasterDetailState(setDetails, details, "ActionDetails", id => ({id}));

return (
<React.Fragment>

<DataToolbar id={"actions"}>
<DataToolbarContent>
<DataToolbarItem>Actions </DataToolbarItem>
<DataToolbarItem variant="separator"/>
<DataToolbarItem><Button variant="primary">Add</Button></DataToolbarItem>
</DataToolbarContent>
</DataToolbar>

<DataList aria-label="data list" selectedDataListItemId={selected}
onSelectDataListItem={onSelect}>
<DataListItem aria-labelledby="selectable-action-item1" id="content-padding-item1">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key="primary content">
<Flex breakpointMods={[{modifier: FlexModifiers.column}]}>
<FlexItem>
<p><strong>anilist</strong></p>
<small>https://pf4.patternfly.org/</small>
</FlexItem>
</Flex>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
</DataList>
</React.Fragment>
)
};
export default ActionList
35 changes: 35 additions & 0 deletions ui/src/pages/Schema/UpstreamDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
DrawerActions,
DrawerCloseButton,
DrawerHead,
DrawerPanelBody,
DrawerPanelContent,
Flex,
FlexItem,
FlexModifiers,
Title
} from '@patternfly/react-core';

import React from 'react';

const UpstreamDetails = ({onClose}) => {

return (<DrawerPanelContent>
<DrawerHead>
<Title headingLevel="h2" size="xl">Details</Title>
<DrawerActions>
<DrawerCloseButton onClick={onClose}/>
</DrawerActions>
</DrawerHead>
<DrawerPanelBody>
<Flex breakpointMods={[{modifier: FlexModifiers["space-items-lg"]}, {modifier: FlexModifiers["column"]}]}>
<FlexItem>
<p>The content of the drawer really is up to you. It could have form fields, definition lists, text lists,
labels, charts, progress bars, etc. Spacing recommendation is 24px margins. You can put tabs in here,
and can also make the drawer scrollable.</p>
</FlexItem>
</Flex>
</DrawerPanelBody>
</DrawerPanelContent>)
};
export default UpstreamDetails
58 changes: 58 additions & 0 deletions ui/src/pages/Schema/UpstreamsList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
Button,
DataList,
DataListCell,
DataListItem,
DataListItemCells,
DataListItemRow,
DataToolbar,
DataToolbarContent,
DataToolbarItem,
Flex,
FlexItem,
FlexModifiers
} from '@patternfly/react-core';

import React from 'react';
import {useMasterDetailState} from "../../components/HasDetails";


const UpstreamList = ({setDetails, details}) => {

const {selected, onSelect} = useMasterDetailState(setDetails, details, "UpstreamDetails", id => ({id}));

return (
<React.Fragment>

<DataToolbar id={"test"}>
<DataToolbarContent>
<DataToolbarItem>Upstream Servers</DataToolbarItem>
<DataToolbarItem variant="separator"/>
<DataToolbarItem><Button variant="primary">Add</Button></DataToolbarItem>
</DataToolbarContent>
</DataToolbar>

<DataList aria-label="data list" selectedDataListItemId={selected}
onSelectDataListItem={onSelect}>
<DataListItem aria-labelledby="selectable-action-item1" id="content-padding-item1">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key="primary content">
<Flex breakpointMods={[{modifier: FlexModifiers.column}]}>
<FlexItem>
<p><strong>anilist</strong></p>
<small>https://pf4.patternfly.org/</small>
</FlexItem>
</Flex>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
</DataList>
</React.Fragment>
)

};
export default UpstreamList
Loading

0 comments on commit 60abf48

Please sign in to comment.