Добавил табы
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 {ArgumentInterface} from "../components/elements/command/elements/argument";
|
||||
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 {
|
||||
class: string,
|
||||
@ -26,12 +31,24 @@ export default function Home({commands}: CommandsInterface) {
|
||||
<link rel="icon" href="/favicon.ico"/>
|
||||
</Head>
|
||||
<main className={styles.main}>
|
||||
<h1>Tasks</h1>
|
||||
<div className={styles.tasks}>
|
||||
{commands.map((command: CommandInterface, index: number) => (
|
||||
<Command key={index} {...command} />
|
||||
))}
|
||||
</div>
|
||||
<Tabs tabsClassName={styles.tabPanel}>
|
||||
<Tab>
|
||||
<TabTitle className={styles.tabPanelItem}>Команды</TabTitle>
|
||||
<TabSection>
|
||||
<div className={styles.tasks}>
|
||||
{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>
|
||||
</>
|
||||
)
|
||||
|
@ -14,3 +14,22 @@
|
||||
display: grid;
|
||||
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