mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-14 20:02:18 +02:00
Fixed web-ui problems
This commit is contained in:
@@ -28,9 +28,7 @@
|
||||
"plugins": [
|
||||
"import",
|
||||
"node",
|
||||
"react",
|
||||
"jest",
|
||||
"@typescript-eslint"
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"consistent-this": [
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
input {
|
||||
color: var(--text-color);
|
||||
font-size: 1.2rem;
|
||||
padding: 0.5rem;
|
||||
border: none;
|
||||
flex: 1 1 auto;
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
@media (max-width:980px) {
|
||||
flex-flow: row wrap;
|
||||
overflow: auto;
|
||||
> * {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
||||
import React, {useCallback, useMemo} from "react";
|
||||
import './server-info-view.scss';
|
||||
import ServerConfig, {ServerInfo} from "../../model/server-config";
|
||||
import {useSnackbar} from "notistack";
|
||||
@@ -43,7 +43,7 @@ export default function ServerInfoView(props: ServerInfoViewProps) {
|
||||
error: (err) => enqueueSnackbar("Failed to save server info!", {variant: 'error'})
|
||||
});
|
||||
}
|
||||
}, [services, enqueueSnackbar]);
|
||||
}, [services, serverInfo, enqueueSnackbar]);
|
||||
|
||||
return <div className={'server-info'}>
|
||||
<div className={'server-info__toolbar'}><label>Server</label>
|
||||
@@ -53,12 +53,12 @@ export default function ServerInfoView(props: ServerInfoViewProps) {
|
||||
<div className={'server-info__content-table'}>
|
||||
{
|
||||
SERVER_INFO_FIELDS.map(field =>
|
||||
<div className={'server-info__content-row'}>
|
||||
<div key={'server_info_field_' + field.name} className={'server-info__content-row'}>
|
||||
<div className={'server-info__content-col'}>
|
||||
<label>{field.caption}</label>
|
||||
</div>
|
||||
<div className={'server-info__content-table-col'}>
|
||||
<input value={(serverInfo as any)?.[field.name]} data-field={field.name}
|
||||
<input defaultValue={(serverInfo as any)?.[field.name]} data-field={field.name}
|
||||
onChange={handleValueChange}></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
.tab-set {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 2px;
|
||||
background-color: var(--tabset-background-color);
|
||||
border-bottom: 1px solid var(--tabset-border-color);
|
||||
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&__tab {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--tab-background-color);
|
||||
color: var(--tab-color);
|
||||
padding: 4px 8px;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
&:focus, &:hover {
|
||||
background-color: var(--tab-hover-background-color);
|
||||
color: var(--tab-hover-color);
|
||||
}
|
||||
|
||||
&-active {
|
||||
border-bottom: 3px solid var(--tab-avtive-indicator-color);
|
||||
background-color: var(--tab-active-background-color);
|
||||
color: var(--tab-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import React, {useCallback} from "react";
|
||||
|
||||
import './tab-set.scss';
|
||||
|
||||
export interface TabSetTab {
|
||||
label: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
interface TabSetProps {
|
||||
tabs: TabSetTab[];
|
||||
active: string;
|
||||
onTabChange: (key: string) => void;
|
||||
}
|
||||
|
||||
export default function TabSet(props: TabSetProps) {
|
||||
const {tabs, active, onTabChange} = props;
|
||||
|
||||
const handleTabClick = useCallback((evt: any) => {
|
||||
const key = evt.target.dataset.key;
|
||||
onTabChange(key);
|
||||
}, [onTabChange]);
|
||||
|
||||
return <ul className={'tab-set'}>
|
||||
{tabs?.map(tab =>
|
||||
<li className={'tab-set__tab' + (tab.key === active ? ' tab-set__tab-active' : '')} key={'tab_' + tab.key} data-key={tab.key} onClick={handleTabClick}>{tab.label}</li>)}
|
||||
</ul>
|
||||
|
||||
}
|
||||
@@ -120,7 +120,7 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 750px) {
|
||||
@media (max-width: 980px) {
|
||||
&-table {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
@@ -140,6 +140,7 @@
|
||||
|
||||
&-col-label {
|
||||
display: block;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
&-col {
|
||||
@@ -148,7 +149,8 @@
|
||||
gap: 4px;
|
||||
|
||||
input {
|
||||
border: 1px solid var(--table-border-color);
|
||||
border-top: 1px solid var(--table-border-color) !important;
|
||||
border-bottom: 1px solid var(--table-border-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import TextGenerator from "../../utils/text-generator";
|
||||
import {useSnackbar} from "notistack";
|
||||
import {useServices} from "../../provider/service-provider";
|
||||
import ConfigUtils from "../../utils/config-utils";
|
||||
import TabSet, {TabSetTab} from "../tab-set/tab-set";
|
||||
|
||||
interface UserViewProps {
|
||||
config: ServerConfig;
|
||||
@@ -17,6 +18,7 @@ export default function UserView(props: UserViewProps) {
|
||||
const {enqueueSnackbar/*, closeSnackbar*/} = useSnackbar();
|
||||
const [targets, setTargets] = useState<TargetUser[]>([]);
|
||||
const [activeTarget, setActiveTarget] = useState<string>(undefined);
|
||||
const [tabs, setTabs] = useState<TabSetTab[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (config) {
|
||||
@@ -30,19 +32,15 @@ export default function UserView(props: UserViewProps) {
|
||||
missing?.forEach(target => {
|
||||
result.push({src: false, target: target.target, credentials: target.credentials} as any);
|
||||
});
|
||||
setTargets(result || []);
|
||||
if (result?.length) {
|
||||
setActiveTarget(result[0].target);
|
||||
const targets = result || [];
|
||||
setTargets(targets);
|
||||
if (targets?.length) {
|
||||
setActiveTarget(targets[0].target);
|
||||
}
|
||||
setTabs(targets.map(target => ({key: target.target, label: target.target})));
|
||||
}
|
||||
}, [config])
|
||||
|
||||
|
||||
const handleTabClick = useCallback((evt: any) => {
|
||||
const target_name = evt.target.dataset.target;
|
||||
setActiveTarget(target_name);
|
||||
}, []);
|
||||
|
||||
const handleUserAdd = useCallback((evt: any) => {
|
||||
const target_name = evt.target.dataset.target;
|
||||
const target = targets.find(target => target.target === target_name);
|
||||
@@ -129,14 +127,16 @@ export default function UserView(props: UserViewProps) {
|
||||
});
|
||||
}, [targets, services, enqueueSnackbar]);
|
||||
|
||||
const handleTabChange = useCallback((target: string) => {
|
||||
setActiveTarget(target);
|
||||
}, []);
|
||||
|
||||
return <div className={'user'}>
|
||||
|
||||
<div className={'user__toolbar'}><label>User</label>
|
||||
<button onClick={handleSave}>Save</button>
|
||||
</div>
|
||||
<div className={'tabset'}>
|
||||
{targets?.map(target => <span className={'tabset__tab' + (target.target === activeTarget ? ' tabset__tab-active' : '')} key={'tab_' + target.target} data-target={target.target} onClick={handleTabClick}>{target.target}</span>)}
|
||||
</div>
|
||||
<TabSet tabs={tabs} active={activeTarget} onTabChange={handleTabChange}></TabSet>
|
||||
<div className={'user__content'}>
|
||||
<div className={'user__content-targets'}>
|
||||
{
|
||||
|
||||
+13
-4
@@ -1,14 +1,23 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import './index.scss';
|
||||
import App from './app/app';
|
||||
import {SnackbarProvider} from 'notistack';
|
||||
import {ServiceProvider} from "./provider/service-provider";
|
||||
|
||||
ReactDOM.render(
|
||||
<SnackbarProvider maxSnack={3} autoHideDuration={1500}>
|
||||
const container = document.getElementById('root');
|
||||
const root = createRoot(container);
|
||||
root.render( <SnackbarProvider maxSnack={3} autoHideDuration={1500}>
|
||||
<ServiceProvider>
|
||||
<App/>
|
||||
</ServiceProvider>
|
||||
</SnackbarProvider>
|
||||
, document.getElementById('root'));
|
||||
);
|
||||
|
||||
// ReactDOM.render(
|
||||
// <SnackbarProvider maxSnack={3} autoHideDuration={1500}>
|
||||
// <ServiceProvider>
|
||||
// <App/>
|
||||
// </ServiceProvider>
|
||||
// </SnackbarProvider>
|
||||
// , document.getElementById('root'));
|
||||
@@ -59,38 +59,6 @@ button {
|
||||
padding: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.tabset {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 2px;
|
||||
background-color: var(--tabset-background-color);
|
||||
border-bottom: 1px solid var(--tabset-border-color);
|
||||
&__tab {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--tab-background-color);
|
||||
color: var(--tab-color);
|
||||
padding: 4px 8px;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
&:focus, &:hover {
|
||||
background-color: var(--tab-hover-background-color);
|
||||
color: var(--tab-hover-color);
|
||||
}
|
||||
|
||||
&-active {
|
||||
border-bottom: 3px solid var(--tab-avtive-indicator-color);
|
||||
background-color: var(--tab-active-background-color);
|
||||
color: var(--tab-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: transparent;
|
||||
|
||||
Reference in New Issue
Block a user