Добавил табы
This commit is contained in:
parent
f885199b2b
commit
f966ee198c
80
components/elements/processes/index.tsx
Normal file
80
components/elements/processes/index.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import styles from './styles.module.css'
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
export interface ProcessExceptionInterface {
|
||||||
|
message: string,
|
||||||
|
file: string,
|
||||||
|
line: bigint,
|
||||||
|
code: bigint,
|
||||||
|
trace: any[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessProgressInterface {
|
||||||
|
total: bigint,
|
||||||
|
progress: bigint,
|
||||||
|
memory: any[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessInterface {
|
||||||
|
id: string,
|
||||||
|
lock: string|null,
|
||||||
|
containerUuid: string|null,
|
||||||
|
pid: bigint|null,
|
||||||
|
name: string,
|
||||||
|
options: Record<string, any>,
|
||||||
|
arguments: Record<string, any>,
|
||||||
|
exception: ProcessExceptionInterface|null,
|
||||||
|
progress: ProcessProgressInterface|null,
|
||||||
|
createdAt: string,
|
||||||
|
updatedAt: string|null,
|
||||||
|
startedAt: string|null,
|
||||||
|
pausedAt: string|null,
|
||||||
|
cancelledAt: string|null
|
||||||
|
completedAt: string|null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Processes() {
|
||||||
|
const [processes, setProcesses] = useState<ProcessInterface[]>([]);
|
||||||
|
|
||||||
|
let refreshProcesses = async () => {
|
||||||
|
let response = await fetch('http://fmw.sipachev.sv/system-monitoring/processes', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8',
|
||||||
|
'X-Plugin-Token': 'passw0rd'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const processes: ProcessInterface[] = await response.json()
|
||||||
|
setProcesses(processes)
|
||||||
|
setTimeout(() => refreshProcesses, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refreshProcesses()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.processes}>
|
||||||
|
{processes.map((process: ProcessInterface, index: number) => (
|
||||||
|
<div className={styles.process} key={index}>
|
||||||
|
<div>
|
||||||
|
{process.name}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{!process.progress && 'N/A'}
|
||||||
|
{process.progress && <span>
|
||||||
|
{`${process.progress.progress}`} / {`${process.progress.total}`} - 50% [53Mb] / 20 sec
|
||||||
|
</span>}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{process.completedAt && <button>Repeat</button>}
|
||||||
|
{process.pausedAt && <button>Play</button>}
|
||||||
|
{!process.pausedAt && !process.completedAt && !process.cancelledAt && <button>Pause</button>}
|
||||||
|
{!process.completedAt && !process.cancelledAt && <button>Stop</button>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
7
components/elements/processes/styles.module.css
Normal file
7
components/elements/processes/styles.module.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.processes {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.process {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 6fr 4fr 2fr;
|
||||||
|
}
|
11
components/elements/tabs/context.ts
Normal file
11
components/elements/tabs/context.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export interface ContextInterface {
|
||||||
|
tabCount: number,
|
||||||
|
tab: number,
|
||||||
|
setTab: (number: number) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Context = React.createContext({} as ContextInterface)
|
||||||
|
export const Provider = Context.Provider
|
||||||
|
export default Context
|
20
components/elements/tabs/elements/tab-section/index.tsx
Normal file
20
components/elements/tabs/elements/tab-section/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React, {PropsWithChildren, useContext} from "react";
|
||||||
|
import TabContext, {Mode} from '../../tab-context'
|
||||||
|
import TabsContext from "../../context";
|
||||||
|
|
||||||
|
const TabSection = ({children}: PropsWithChildren<any>) => {
|
||||||
|
const {tab: activeTab} = useContext(TabsContext)
|
||||||
|
const {tab, mode} = useContext(TabContext)
|
||||||
|
|
||||||
|
if (Mode.SECTIONS !== mode) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeTab !== tab) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabSection
|
20
components/elements/tabs/elements/tab-title/index.tsx
Normal file
20
components/elements/tabs/elements/tab-title/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React, {PropsWithChildren, useContext} from "react";
|
||||||
|
import TabsContext from '../../context'
|
||||||
|
import TabContext, {Mode} from '../../tab-context'
|
||||||
|
|
||||||
|
const TabTitle = ({children, className}: PropsWithChildren<any>) => {
|
||||||
|
const {setTab} = useContext(TabsContext)
|
||||||
|
const {tab, mode} = useContext(TabContext)
|
||||||
|
|
||||||
|
if (Mode.TABS !== mode) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={className} onClick={() => {setTab(tab)}}>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabTitle
|
20
components/elements/tabs/elements/tab/index.tsx
Normal file
20
components/elements/tabs/elements/tab/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React, {Fragment} from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: React.ReactNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tab = ({children}: Props) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{children.map((child: React.ReactNode, index: number) => {
|
||||||
|
return (
|
||||||
|
<Fragment key={index}>{child}</Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tab
|
||||||
|
|
46
components/elements/tabs/index.tsx
Normal file
46
components/elements/tabs/index.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import React, {FC, Fragment, useState} from "react";
|
||||||
|
import {Provider} from './context'
|
||||||
|
import {Mode, Provider as TabProvider} from './tab-context'
|
||||||
|
|
||||||
|
interface ITabs {
|
||||||
|
children: React.ReactNode[];
|
||||||
|
tabsClassName?: string;
|
||||||
|
sectionsClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tabs: FC<ITabs> = ({children, tabsClassName, sectionsClassName}) => {
|
||||||
|
const [tab, setTab] = useState<number>(0)
|
||||||
|
const tabCount = children.length
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Provider value={{tabCount, tab, setTab}}>
|
||||||
|
<div className={tabsClassName}>
|
||||||
|
{children.map((child: React.ReactNode, index: number) => {
|
||||||
|
return (
|
||||||
|
<Fragment key={index}>
|
||||||
|
<TabProvider value={{tab:index, mode: Mode.TABS}}>
|
||||||
|
{child}
|
||||||
|
</TabProvider>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={sectionsClassName}>
|
||||||
|
{children.map((child: React.ReactNode, index: number) => {
|
||||||
|
return (
|
||||||
|
<Fragment key={index}>
|
||||||
|
<TabProvider value={{tab:index, mode: Mode.SECTIONS }}>
|
||||||
|
{child}
|
||||||
|
</TabProvider>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Provider>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tabs
|
||||||
|
|
15
components/elements/tabs/tab-context.ts
Normal file
15
components/elements/tabs/tab-context.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export enum Mode {
|
||||||
|
TABS,
|
||||||
|
SECTIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContextInterface {
|
||||||
|
tab: number,
|
||||||
|
mode: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Context = React.createContext({} as ContextInterface)
|
||||||
|
export const Provider = Context.Provider
|
||||||
|
export default Context
|
@ -3,6 +3,11 @@ import styles from '../styles/Home.module.css'
|
|||||||
import {OptionInterface} from "../components/elements/command/elements/option";
|
import {OptionInterface} from "../components/elements/command/elements/option";
|
||||||
import {ArgumentInterface} from "../components/elements/command/elements/argument";
|
import {ArgumentInterface} from "../components/elements/command/elements/argument";
|
||||||
import Command from "../components/elements/command";
|
import Command from "../components/elements/command";
|
||||||
|
import Tabs from "../components/elements/tabs";
|
||||||
|
import Tab from "../components/elements/tabs/elements/tab";
|
||||||
|
import TabTitle from "../components/elements/tabs/elements/tab-title";
|
||||||
|
import TabSection from "../components/elements/tabs/elements/tab-section";
|
||||||
|
import Processes from "../components/elements/processes";
|
||||||
|
|
||||||
interface CommandInterface {
|
interface CommandInterface {
|
||||||
class: string,
|
class: string,
|
||||||
@ -26,12 +31,24 @@ export default function Home({commands}: CommandsInterface) {
|
|||||||
<link rel="icon" href="/favicon.ico"/>
|
<link rel="icon" href="/favicon.ico"/>
|
||||||
</Head>
|
</Head>
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<h1>Tasks</h1>
|
<Tabs tabsClassName={styles.tabPanel}>
|
||||||
<div className={styles.tasks}>
|
<Tab>
|
||||||
{commands.map((command: CommandInterface, index: number) => (
|
<TabTitle className={styles.tabPanelItem}>Команды</TabTitle>
|
||||||
<Command key={index} {...command} />
|
<TabSection>
|
||||||
))}
|
<div className={styles.tasks}>
|
||||||
</div>
|
{commands.map((command: CommandInterface, index: number) => (
|
||||||
|
<Command key={index} {...command} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</TabSection>
|
||||||
|
</Tab>
|
||||||
|
<Tab>
|
||||||
|
<TabTitle className={styles.tabPanelItem}>Процессы</TabTitle>
|
||||||
|
<TabSection>
|
||||||
|
<Processes />
|
||||||
|
</TabSection>
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -14,3 +14,22 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 11fr 1fr;
|
grid-template-columns: 11fr 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabPanel {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabPanelItem {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: solid 2px #cae5fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabPanelItem:hover {
|
||||||
|
border-bottom: solid 2px #298df8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabPanelItemActive {
|
||||||
|
border-bottom: solid 2px #298df8;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user