updated ui
This commit is contained in:
parent
c7667ec5b5
commit
2ebcf0a8c4
20976
package-lock.json
generated
20976
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
name: "a-cool-games-manager",
|
"name": "a-cool-games-manager",
|
||||||
version: "0.1.0",
|
"version": "0.1.0",
|
||||||
private: true,
|
"private": true,
|
||||||
dependencies: {
|
"dependencies": {
|
||||||
"@rjsf/core": "^5.14.2",
|
"@rjsf/core": "^5.14.2",
|
||||||
"@rjsf/mui": "^5.14.2",
|
"@rjsf/mui": "^5.14.2",
|
||||||
"@rjsf/utils": "^5.14.2",
|
"@rjsf/utils": "^5.14.2",
|
||||||
@ -16,39 +16,39 @@
|
|||||||
"@types/react": "^18.2.38",
|
"@types/react": "^18.2.38",
|
||||||
"@types/react-dom": "^18.2.16",
|
"@types/react-dom": "^18.2.16",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
axios: "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
dotenv: "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
jsonpath: "^1.1.1",
|
"jsonpath": "^1.1.1",
|
||||||
react: "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-jsonschema-form": "^1.8.1",
|
"react-jsonschema-form": "^1.8.1",
|
||||||
"react-router-dom": "^6.19.0",
|
"react-router-dom": "^6.19.0",
|
||||||
"react-routes": "^0.2.6",
|
"react-routes": "^0.2.6",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
serve: "^14.2.1",
|
"serve": "^14.2.1",
|
||||||
typescript: "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
scripts: {
|
"scripts": {
|
||||||
start: "react-scripts start",
|
"start": "react-scripts start",
|
||||||
build: "/usr/bin/env react-scripts build",
|
"build": "/usr/bin/env react-scripts build",
|
||||||
test: "react-scripts test",
|
"test": "react-scripts test",
|
||||||
eject: "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
eslintConfig: {
|
"eslintConfig": {
|
||||||
extends: [
|
"extends": [
|
||||||
"react-app",
|
"react-app",
|
||||||
"react-app/jest"
|
"react-app/jest"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
browserslist: {
|
"browserslist": {
|
||||||
production: [
|
"production": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
"not dead",
|
"not dead",
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
],
|
],
|
||||||
development: [
|
"development": [
|
||||||
"last 1 chrome version",
|
"last 1 chrome version",
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
short_name: "React App",
|
"short_name": "React App",
|
||||||
name: "Create React App Sample",
|
"name": "Create React App Sample",
|
||||||
icons: [
|
"icons": [
|
||||||
{
|
{
|
||||||
src: "favicon.ico",
|
"src": "favicon.ico",
|
||||||
sizes: "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
type: "image/x-icon"
|
"type": "image/x-icon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "logo192.png",
|
"src": "logo192.png",
|
||||||
type: "image/png",
|
"type": "image/png",
|
||||||
sizes: "192x192"
|
"sizes": "192x192"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "logo512.png",
|
"src": "logo512.png",
|
||||||
type: "image/png",
|
"type": "image/png",
|
||||||
sizes: "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
start_url: ".",
|
"start_url": ".",
|
||||||
display: "standalone",
|
"display": "standalone",
|
||||||
theme_color: "#000000",
|
"theme_color": "#000000",
|
||||||
background_color: "#ffffff"
|
"background_color": "#ffffff"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Box, Paper, ThemeProvider, List, ListItem, ListItemButton, ListItemText, SwipeableDrawer, ListItemIcon, IconButton, AppBar, Toolbar, PaletteMode, createTheme, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, Paper, ThemeProvider, List, ListItem, ListItemButton, ListItemText, SwipeableDrawer, ListItemIcon, IconButton, AppBar, Toolbar, PaletteMode, createTheme, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import React, { Dispatch, ReactNode, useState } from "react";
|
import React, { Dispatch, ReactNode } from "react";
|
||||||
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
||||||
import { ApiWrapper, getDesignTokens, GlobalOpenApi, GlobalUserInfo } from "./common";
|
import { ApiWrapper, getDesignTokens, GlobalUserInfo } from "./common";
|
||||||
import { LoginPage } from "./login";
|
import { LoginPage } from "./login";
|
||||||
import ServersBoard from "./servers";
|
import ServersBoard from "./servers";
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
@ -121,7 +121,6 @@ export default function App() {
|
|||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ApiWrapper>
|
<ApiWrapper>
|
||||||
<GlobalOpenApi>
|
|
||||||
<GlobalUserInfo>
|
<GlobalUserInfo>
|
||||||
<Menu setMode={setMode}>
|
<Menu setMode={setMode}>
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -134,7 +133,6 @@ export default function App() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
</Menu>
|
</Menu>
|
||||||
</GlobalUserInfo>
|
</GlobalUserInfo>
|
||||||
</GlobalOpenApi>
|
|
||||||
</ApiWrapper>
|
</ApiWrapper>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
@ -596,3 +596,27 @@ export const SERVER_ACTIONS: ActionInfo[] = [
|
|||||||
response_action: "Ignore"
|
response_action: "Ignore"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const CREATE_SERVER_ACTION: ActionInfo = {
|
||||||
|
name: "Create Server",
|
||||||
|
args: {
|
||||||
|
"$ref": "#/definitions/CreateServer",
|
||||||
|
definitions: definitions,
|
||||||
|
},
|
||||||
|
requestType: "post",
|
||||||
|
endpoint: "/servers",
|
||||||
|
permissions: Permission.Create,
|
||||||
|
response_action: "Ignore"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const INVITE_USER_ACTION: ActionInfo = {
|
||||||
|
name: "Create Server",
|
||||||
|
args: {
|
||||||
|
"$ref": "#/definitions/InviteUserRequests",
|
||||||
|
definitions: definitions,
|
||||||
|
},
|
||||||
|
requestType: "post",
|
||||||
|
endpoint: "/users",
|
||||||
|
permissions: Permission.Admin,
|
||||||
|
response_action: "Ignore"
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { TableRow, TableCell, TableContainer, TableHead, Table, Button, Popover, Paper, TableBody, Chip, Link, ButtonGroup, Modal, Box } from "@mui/material"
|
import { TableRow, TableCell, TableContainer, TableHead, Table, Button, Popover, Paper, TableBody, Chip, Link, ButtonGroup, Modal, Box } from "@mui/material"
|
||||||
import React, { useContext, Dispatch, useState, useEffect, createContext, Context } from "react"
|
import React, { useContext, Dispatch, useState, useEffect, createContext, Context } from "react"
|
||||||
import Form from "@rjsf/mui"
|
import Form from "@rjsf/mui"
|
||||||
import { apiAuthenticatedContext, useApiDoc, api, ActionItem, formModalStyle, DataTable, useActions, ActionInfo, ActionGroup, actionIdentifierContext } from "./common"
|
import { apiAuthenticatedContext, api, DataTable, ActionInfo, ActionGroup, actionIdentifierContext } from "./common"
|
||||||
import validator from '@rjsf/validator-ajv8';
|
import validator from '@rjsf/validator-ajv8';
|
||||||
import { Browser, ServerInfo } from "./interfaces";
|
import { Browser, ServerInfo } from "./interfaces";
|
||||||
import { loadServers } from "./servers";
|
import { loadServers } from "./servers";
|
||||||
@ -85,7 +85,7 @@ export function BrowsersPage({ }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <DataTable headers={['Browser Owner', 'Server Owner', 'Server Game', 'Game Version', 'Actions']}>
|
return <DataTable headers={['Browser Owner', 'Server Owner', 'Server Game', 'Game Version', 'Actions']}>
|
||||||
<browserActionContext.Provider value={useActions(api, '/browsers/{browser_id}')}>
|
<browserActionContext.Provider value={[]}>
|
||||||
{browserComponents}
|
{browserComponents}
|
||||||
</browserActionContext.Provider>
|
</browserActionContext.Provider>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
128
src/common.tsx
128
src/common.tsx
@ -79,8 +79,6 @@ export const api: AxiosInstance = axios.create({
|
|||||||
baseURL: API_URL,
|
baseURL: API_URL,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(process.env)
|
|
||||||
|
|
||||||
export function ApiWrapper(p: { children: ReactNode}) {
|
export function ApiWrapper(p: { children: ReactNode}) {
|
||||||
const {children} = p
|
const {children} = p
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
@ -99,34 +97,6 @@ export function ApiWrapper(p: { children: ReactNode}) {
|
|||||||
</apiAuthenticatedContext.Provider>)
|
</apiAuthenticatedContext.Provider>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function useApiDoc(api: AxiosInstance, path: string, method: 'get' | 'post' | 'delete') {
|
|
||||||
const [apiRecord, setApiRecord] = useState(null as OpenAPISchema|null)
|
|
||||||
api.get('/openapi.json').then(
|
|
||||||
(value) => {
|
|
||||||
setApiRecord(value.data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (apiRecord) {
|
|
||||||
const schema = apiRecord.paths[path][method]
|
|
||||||
if (!schema){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let formSchema: JSONSchema7 = { title: schema.summary, type: 'object', required: [], properties: {}, definitions: apiRecord.components, default: {} }
|
|
||||||
if (schema.requestBody) {
|
|
||||||
formSchema = schema.requestBody.content['application/json'].schema
|
|
||||||
formSchema.definitions = apiRecord.components
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parse(JSON.stringify(formSchema).replaceAll('#/components', '#/definitions'))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface ActionInfo {
|
export interface ActionInfo {
|
||||||
name: string
|
name: string
|
||||||
requestType: 'post' | 'get' | 'delete'
|
requestType: 'post' | 'get' | 'delete'
|
||||||
@ -137,87 +107,6 @@ export interface ActionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function useActions(api: AxiosInstance, path_prefix: string): ActionInfo[] {
|
|
||||||
const openapi: OpenAPISchema|null = useContext(OpenApiContext)
|
|
||||||
let [actions, setActions]: [Record<string, ActionInfo[]>, Dispatch<Record<string, ActionInfo[]>>] = useState({})
|
|
||||||
console.log(actions)
|
|
||||||
if (actions[path_prefix] && actions[path_prefix].length > 0) {
|
|
||||||
return actions[path_prefix]
|
|
||||||
}
|
|
||||||
if (openapi === null) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
let responseActions: ActionInfo[] = []
|
|
||||||
let paths = openapi.paths
|
|
||||||
for (let [path, request] of Object.entries(paths)) {
|
|
||||||
if (path.startsWith(path_prefix)) {
|
|
||||||
for (let [method, schema] of Object.entries(request)) {
|
|
||||||
let formSchema: JSONSchema7 = { title: schema.summary, type: 'object', required: [], properties: {}, definitions: openapi.components, default: {} }
|
|
||||||
if (schema.requestBody) {
|
|
||||||
formSchema = schema.requestBody.content['application/json'].schema
|
|
||||||
formSchema.definitions = openapi.components
|
|
||||||
}
|
|
||||||
responseActions.push(
|
|
||||||
{
|
|
||||||
name: schema.summary,
|
|
||||||
args: formSchema,
|
|
||||||
requestType: (method as 'get' | 'post' | 'delete'),
|
|
||||||
endpoint: path,
|
|
||||||
permissions: schema.permissions,
|
|
||||||
response_action: schema.api_response,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actions[path_prefix] = responseActions
|
|
||||||
setActions(actions)
|
|
||||||
|
|
||||||
if (actions[path_prefix]) {
|
|
||||||
return actions[path_prefix]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAction(p: {path: string, method: 'post' | 'get' | 'delete'}): ActionInfo|undefined{
|
|
||||||
const apiDoc: OpenAPISchema|null = useContext(OpenApiContext)
|
|
||||||
const [action, setAction]: [ActionInfo|null, Dispatch<ActionInfo|null>] = useState(null as ActionInfo|null)
|
|
||||||
if (action != null){
|
|
||||||
return action
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!apiDoc){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const schema = apiDoc.paths[p.path][p.method]
|
|
||||||
if (!schema){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let formSchema: JSONSchema7 = { title: schema.summary, type: 'object', required: [], properties: {}, definitions: apiDoc.components, default: {} }
|
|
||||||
if (schema.requestBody) {
|
|
||||||
formSchema = schema.requestBody.content['application/json'].schema
|
|
||||||
formSchema.definitions = apiDoc.components
|
|
||||||
}
|
|
||||||
const calculatedAction = {
|
|
||||||
name: schema.summary,
|
|
||||||
args: JSON.parse(JSON.stringify(formSchema).replaceAll('#/components', '#/definitions')),
|
|
||||||
requestType: p.method,
|
|
||||||
endpoint: p.path,
|
|
||||||
permissions: schema.permissions,
|
|
||||||
response_action: schema.api_response,
|
|
||||||
}
|
|
||||||
setAction(calculatedAction)
|
|
||||||
|
|
||||||
return calculatedAction
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface Options{
|
interface Options{
|
||||||
label: string
|
label: string
|
||||||
const: string
|
const: string
|
||||||
@ -253,6 +142,7 @@ function FetcherField(props: WidgetProps){
|
|||||||
|
|
||||||
|
|
||||||
function isUserAllowed(user: User|null, action: ActionInfo): boolean{
|
function isUserAllowed(user: User|null, action: ActionInfo): boolean{
|
||||||
|
console.log({User: user, Action: action})
|
||||||
if (user === null){
|
if (user === null){
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -468,19 +358,3 @@ export function GlobalUserInfo(props: {children: any}){
|
|||||||
{props.children}
|
{props.children}
|
||||||
</UserInfoContext.Provider>
|
</UserInfoContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const OpenApiContext: Context<OpenAPISchema|null> = createContext(null as OpenAPISchema|null)
|
|
||||||
export function GlobalOpenApi(props: {children: any}){
|
|
||||||
const [openApi, setOpenApi]: [OpenAPISchema|null, Dispatch<OpenAPISchema|null>] = useState(null as OpenAPISchema|null)
|
|
||||||
if (openApi === null){
|
|
||||||
api.get('/openapi.json').then((event)=>{
|
|
||||||
setOpenApi(event.data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return <OpenApiContext.Provider value={openApi}>
|
|
||||||
{props.children}
|
|
||||||
</OpenApiContext.Provider>
|
|
||||||
}
|
|
||||||
|
@ -6,14 +6,14 @@ import Cookies from 'js-cookie'
|
|||||||
|
|
||||||
export const fetchToken = async (username: string, password: string, remember: boolean) => {
|
export const fetchToken = async (username: string, password: string, remember: boolean) => {
|
||||||
try {
|
try {
|
||||||
const response = await api.post('/token', {
|
const response = await api.post('/auth/signin', {
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
remember: remember,
|
remember: remember,
|
||||||
}, {
|
}, {
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
});
|
});
|
||||||
return response.data.access_token;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching token:', error);
|
console.error('Error fetching token:', error);
|
||||||
throw error;
|
throw error;
|
||||||
@ -41,7 +41,7 @@ export function LoginPage(props: {}) {
|
|||||||
fetchToken(username, password, Boolean(data.get('remember'))).then(
|
fetchToken(username, password, Boolean(data.get('remember'))).then(
|
||||||
(token) => {
|
(token) => {
|
||||||
api.defaults.headers.common.Authorization = `Bearer ${token}`;
|
api.defaults.headers.common.Authorization = `Bearer ${token}`;
|
||||||
localStorage.setItem('token', token)
|
Cookies.set('auth', token)
|
||||||
setApiAuthenticated(true)
|
setApiAuthenticated(true)
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { AxiosInstance } from "axios"
|
import { AxiosInstance } from "axios"
|
||||||
import { ActionGroup, ActionInfo, DataTable, UserInfoContext, actionIdentifierContext, api, apiAuthenticatedContext, useAction, useActions } from "./common"
|
import { ActionGroup, ActionInfo, DataTable, UserInfoContext, actionIdentifierContext, api, apiAuthenticatedContext} from "./common"
|
||||||
import React, { Context, Dispatch, createContext, useContext, useEffect, useState } from "react"
|
import React, { Context, Dispatch, createContext, useContext, useEffect, useState } from "react"
|
||||||
import { TableRow, TableCell, Chip } from "@mui/material"
|
import { TableRow, TableCell, Chip } from "@mui/material"
|
||||||
import { ImageInfo, ServerInfo } from "./interfaces"
|
import { ImageInfo, ServerInfo } from "./interfaces"
|
||||||
import { JSONSchema7 } from "json-schema"
|
import { JSONSchema7 } from "json-schema"
|
||||||
import { Permission, SERVER_ACTIONS } from "./actions"
|
import { CREATE_SERVER_ACTION, Permission, SERVER_ACTIONS } from "./actions"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ function ServerItem(props: { server_info: ServerInfo }) {
|
|||||||
const [serverPermissions, setServerPermissions] = useState(null as null|number)
|
const [serverPermissions, setServerPermissions] = useState(null as null|number)
|
||||||
const user = useContext(UserInfoContext)
|
const user = useContext(UserInfoContext)
|
||||||
let permissions = 0
|
let permissions = 0
|
||||||
|
console.log(user)
|
||||||
if (props.server_info.OwnerId === user?.Username){
|
if (props.server_info.OwnerId === user?.Username){
|
||||||
permissions |= Permission.Admin
|
permissions |= Permission.Admin
|
||||||
}else{
|
}else{
|
||||||
@ -68,23 +68,6 @@ function ServerItem(props: { server_info: ServerInfo }) {
|
|||||||
export default function ServersBoard() {
|
export default function ServersBoard() {
|
||||||
const [servers, setServers]: [ServerInfo[], Dispatch<ServerInfo[]>] = useState([] as ServerInfo[]);
|
const [servers, setServers]: [ServerInfo[], Dispatch<ServerInfo[]>] = useState([] as ServerInfo[]);
|
||||||
const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext)
|
const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext)
|
||||||
const [images, setImages] = useState([] as ImageInfo[])
|
|
||||||
|
|
||||||
let schema: JSONSchema7 = {
|
|
||||||
properties: {
|
|
||||||
image_id: {
|
|
||||||
type: "string",
|
|
||||||
oneOf: images.map((value, index, array) => { return { const: value.Id, title: `${value.Name} ${value.Version}` } }),
|
|
||||||
title: "Image Id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
type: "object",
|
|
||||||
required: [
|
|
||||||
"image_id"
|
|
||||||
],
|
|
||||||
title: "CreateServer"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function handleServers() {
|
function handleServers() {
|
||||||
if (!apiAuthenticated) {
|
if (!apiAuthenticated) {
|
||||||
@ -123,23 +106,7 @@ export default function ServersBoard() {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable headers={['Nickname', 'Owner', 'Server', 'Version', 'Domain', 'Ports', 'Actions']} actionInfo={useAction({path: '/servers', method: 'post'})} actionHook={() => {
|
<DataTable headers={['Nickname', 'Owner', 'Server', 'Version', 'Domain', 'Ports', 'Actions']} actionInfo={CREATE_SERVER_ACTION}>
|
||||||
api.get('/images').then((value) => {
|
|
||||||
setImages(value.data)
|
|
||||||
}).catch(
|
|
||||||
(error) => {
|
|
||||||
console.log('Failed to get images: ' + error);
|
|
||||||
if (error.response) {
|
|
||||||
if (error.response.status === 401) {
|
|
||||||
setApiAuthenticated(false)
|
|
||||||
}
|
|
||||||
else if (error.response.status === 403) {
|
|
||||||
setApiAuthenticated(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}}>
|
|
||||||
<serverActionsContext.Provider value={SERVER_ACTIONS}>
|
<serverActionsContext.Provider value={SERVER_ACTIONS}>
|
||||||
{
|
{
|
||||||
servers.sort((s1: ServerInfo, s2: ServerInfo) => { return s1.Id < s2.Id ? 0 : 1 }).map(
|
servers.sort((s1: ServerInfo, s2: ServerInfo) => { return s1.Id < s2.Id ? 0 : 1 }).map(
|
||||||
|
@ -1,12 +1,35 @@
|
|||||||
import { TableRow, TableCell, TableContainer, TableHead, Table, Button, Paper, TableBody, Chip, Modal, Box } from "@mui/material"
|
import { TableRow, TableCell, Chip } from "@mui/material"
|
||||||
import React, { useContext, Dispatch, useState, useEffect, Context, createContext } from "react"
|
import { useContext, Dispatch, useState, useEffect, Context, createContext } from "react"
|
||||||
import Form from "@rjsf/mui"
|
import { apiAuthenticatedContext, api, ActionInfo, ActionGroup, actionIdentifierContext, DataTable } from "./common"
|
||||||
import { apiAuthenticatedContext, useApiDoc, api, ActionInfo, useActions, ActionGroup, actionIdentifierContext, ActionItem, DataTable, useAction } from "./common"
|
|
||||||
import validator from '@rjsf/validator-ajv8';
|
|
||||||
import { User } from './interfaces'
|
import { User } from './interfaces'
|
||||||
|
import { INVITE_USER_ACTION, Permission } from "./actions";
|
||||||
|
|
||||||
const UserActionsContext: Context<ActionInfo[]> = createContext([] as ActionInfo[])
|
const UserActionsContext: Context<ActionInfo[]> = createContext([] as ActionInfo[])
|
||||||
|
function getPermissionStrings(permissions: number){
|
||||||
|
let strings = []
|
||||||
|
if (permissions & Permission.Admin){
|
||||||
|
strings.push("Admin")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.Start){
|
||||||
|
strings.push("Start")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.Stop){
|
||||||
|
strings.push("Stop")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.Browse){
|
||||||
|
strings.push("Browse")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.Create){
|
||||||
|
strings.push("Create")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.Delete){
|
||||||
|
strings.push("Delete")
|
||||||
|
}
|
||||||
|
if (permissions & Permission.RunCommand){
|
||||||
|
strings.push("RunCommand")
|
||||||
|
}
|
||||||
|
return strings
|
||||||
|
}
|
||||||
|
|
||||||
function UserItem(p: { user: User }) {
|
function UserItem(p: { user: User }) {
|
||||||
const user = p.user;
|
const user = p.user;
|
||||||
@ -16,7 +39,7 @@ function UserItem(p: { user: User }) {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>{user.Username}</TableCell>
|
<TableCell>{user.Username}</TableCell>
|
||||||
<TableCell>{user.Email}</TableCell>
|
<TableCell>{user.Email}</TableCell>
|
||||||
<TableCell>{user.Permissions.map((value, index, array) => { return <Chip label={value} /> })}</TableCell>
|
<TableCell>{getPermissionStrings(user.Permissions).map((value, index, array) => { return <Chip label={value} /> })}</TableCell>
|
||||||
<TableCell><ActionGroup actions={userActions} identifierSubstring="username" /></TableCell>
|
<TableCell><ActionGroup actions={userActions} identifierSubstring="username" /></TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
)
|
||||||
@ -26,7 +49,7 @@ export function UsersPage({ }) {
|
|||||||
const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext)
|
const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext)
|
||||||
const [users, setUsers]: [User[], Dispatch<User[]>] = useState([] as User[])
|
const [users, setUsers]: [User[], Dispatch<User[]>] = useState([] as User[])
|
||||||
|
|
||||||
const action: ActionInfo|undefined = useAction({path: '/users', method: 'post'})
|
const action: ActionInfo|undefined = INVITE_USER_ACTION
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!apiAuthenticated) {
|
if (!apiAuthenticated) {
|
||||||
@ -73,7 +96,7 @@ export function UsersPage({ }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <DataTable headers={['Username', 'Email', 'Permissions', 'Actions']} actionInfo={action}>
|
return <DataTable headers={['Username', 'Email', 'Permissions', 'Actions']} actionInfo={action}>
|
||||||
<UserActionsContext.Provider value={useActions(api, '/users/{username}')}>
|
<UserActionsContext.Provider value={[]}>
|
||||||
{userComponents}
|
{userComponents}
|
||||||
</UserActionsContext.Provider>
|
</UserActionsContext.Provider>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
{
|
{
|
||||||
compilerOptions: {
|
"compilerOptions": {
|
||||||
target: "es5",
|
"target": "es5",
|
||||||
lib: [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"dom.iterable",
|
"dom.iterable",
|
||||||
"esnext"
|
"esnext"
|
||||||
],
|
],
|
||||||
allowJs: true,
|
"allowJs": true,
|
||||||
skipLibCheck: true,
|
"skipLibCheck": true,
|
||||||
esModuleInterop: true,
|
"esModuleInterop": true,
|
||||||
allowSyntheticDefaultImports: true,
|
"allowSyntheticDefaultImports": true,
|
||||||
strict: true,
|
"strict": true,
|
||||||
forceConsistentCasingInFileNames: true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
noFallthroughCasesInSwitch: true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
module: "esnext",
|
"module": "esnext",
|
||||||
moduleResolution: "node",
|
"moduleResolution": "node",
|
||||||
resolveJsonModule: true,
|
"resolveJsonModule": true,
|
||||||
isolatedModules: true,
|
"isolatedModules": true,
|
||||||
noEmit: true,
|
"noEmit": true,
|
||||||
jsx: "react-jsx"
|
"jsx": "react-jsx"
|
||||||
},
|
},
|
||||||
include: [
|
"include": [
|
||||||
"src"
|
"src"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user