1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-15 18:00:05 +00:00

chore(log): used css module to declare classes

This commit is contained in:
Yury Shkoda
2023-04-27 17:52:57 +03:00
parent 777b3a55be
commit 87e9172cfc
9 changed files with 856 additions and 297 deletions

888
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,7 @@
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"typescript": "^4.5.2", "typescript": "^4.5.2",
"typescript-plugin-css-modules": "^5.0.1",
"webpack": "5.64.3", "webpack": "5.64.3",
"webpack-cli": "^4.9.2", "webpack-cli": "^4.9.2",
"webpack-dev-server": "4.7.4" "webpack-dev-server": "4.7.4"

View File

@@ -0,0 +1,86 @@
.ChunkHeader {
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 1px -1px,
rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px;
}
.ChunkDetails {
display: flex;
flex-direction: row;
gap: 6px;
align-items: center;
}
.ChunkExpandIcon {
margin-left: auto;
}
.ChunkBody {
background-color: white;
overflow: hidden;
}
.ChunksContainer {
display: flex;
flex-direction: column;
gap: 10px;
}
.LogContainer {
background-color: #fbfbfb;
border: 1px solid #e2e2e2;
border-radius: 3px;
min-height: 50px;
padding: 10px;
box-sizing: border-box;
white-space: pre-wrap;
font-family: Monaco, Courier, monospace;
position: relative;
width: 100%;
}
.LogWrapper {
overflow-y: auto;
max-height: calc(100vh - 130px);
}
.LogBody {
overflow: auto;
height: calc(100vh - 220px);
}
.TreeContainer {
background-color: white;
padding-top: 10px;
padding-bottom: 10px;
}
.TabContainer {
display: flex;
flex-direction: row;
gap: 6px;
align-items: center;
}
.TabDownloadIcon {
margin-left: 20px;
}
.HighlightedLine {
background-color: #f6e30599;
}
.Icon {
font-size: 20px !important;
}
.GreenIcon {
color: green;
}

View File

@@ -6,7 +6,6 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import CheckIcon from '@mui/icons-material/Check' import CheckIcon from '@mui/icons-material/Check'
import FileDownloadIcon from '@mui/icons-material/FileDownload' import FileDownloadIcon from '@mui/icons-material/FileDownload'
import { makeStyles } from '@mui/styles'
import { import {
defaultChunkSize, defaultChunkSize,
parseErrorsAndWarnings, parseErrorsAndWarnings,
@@ -14,27 +13,8 @@ import {
clearErrorsAndWarningsHtmlWrapping, clearErrorsAndWarningsHtmlWrapping,
download download
} from '../../../../../utils' } from '../../../../../utils'
import { logStyles } from './logComponent'
const useStyles: any = makeStyles((theme: any) => ({ import classes from './log.module.css'
expansionDescription: {
backgroundColor: '#fbfbfb',
border: '1px solid #e2e2e2',
borderRadius: '3px',
minHeight: '50px',
padding: '10px',
boxSizing: 'border-box',
whiteSpace: 'pre-wrap',
fontFamily: 'Monaco, Courier, monospace',
position: 'relative',
width: '100%',
[theme.breakpoints.down('sm')]: {
fontSize: theme.typography.pxToRem(12)
},
[theme.breakpoints.up('md')]: {
fontSize: theme.typography.pxToRem(16)
}
}
}))
interface LogChunkProps { interface LogChunkProps {
id: number id: number
@@ -51,7 +31,7 @@ const LogChunk = (props: LogChunkProps) => {
props.scrollToLogInstance props.scrollToLogInstance
) )
const rowText = clearErrorsAndWarningsHtmlWrapping(text) const rowText = clearErrorsAndWarningsHtmlWrapping(text)
const classes = useStyles() const styles = logStyles()
const [expanded, setExpanded] = useState(props.expanded) const [expanded, setExpanded] = useState(props.expanded)
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
@@ -93,35 +73,17 @@ const LogChunk = (props: LogChunkProps) => {
return ( return (
<div onClick={(evt) => props.onClick(evt, id)}> <div onClick={(evt) => props.onClick(evt, id)}>
<button <button className={classes.ChunkHeader}>
style={{
color: '#444',
cursor: 'pointer',
padding: '18px',
width: '100%',
textAlign: 'left',
border: 'none',
outline: 'none',
transition: '0.4s',
boxShadow:
'rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px'
}}
>
<Typography variant="subtitle1"> <Typography variant="subtitle1">
<div <div className={classes.ChunkDetails}>
style={{
display: 'flex',
flexDirection: 'row',
gap: 6,
alignItems: 'center'
}}
>
<span>{`Lines: ${getLineRange()}`}</span> <span>{`Lines: ${getLineRange()}`}</span>
{copied ? ( {copied ? (
<CheckIcon style={{ fontSize: 20, color: 'green' }} /> <CheckIcon
className={[classes.Icon, classes.GreenIcon].join(' ')}
/>
) : ( ) : (
<ContentCopyIcon <ContentCopyIcon
style={{ fontSize: 20 }} className={classes.Icon}
onClick={(evt: SyntheticEvent) => { onClick={(evt: SyntheticEvent) => {
evt.stopPropagation() evt.stopPropagation()
@@ -143,7 +105,7 @@ const LogChunk = (props: LogChunkProps) => {
{errors && errors.length !== 0 && ( {errors && errors.length !== 0 && (
<ErrorOutline <ErrorOutline
color="error" color="error"
style={{ fontSize: 20 }} className={classes.Icon}
onClick={() => { onClick={() => {
setScrollToLogInstance(errors[0]) setScrollToLogInstance(errors[0])
}} }}
@@ -151,15 +113,17 @@ const LogChunk = (props: LogChunkProps) => {
)} )}
{warnings && warnings.length !== 0 && ( {warnings && warnings.length !== 0 && (
<Warning <Warning
style={{ fontSize: 20, color: 'green' }} className={[classes.Icon, classes.GreenIcon].join(' ')}
onClick={() => { onClick={(evt) => {
if (expanded) evt.stopPropagation()
setScrollToLogInstance(warnings[0]) setScrollToLogInstance(warnings[0])
}} }}
/> />
)}{' '} )}{' '}
<ExpandMoreIcon <ExpandMoreIcon
className={classes.ChunkExpandIcon}
style={{ style={{
marginLeft: 'auto',
transform: expanded ? 'rotate(180deg)' : 'unset' transform: expanded ? 'rotate(180deg)' : 'unset'
}} }}
/> />
@@ -167,13 +131,17 @@ const LogChunk = (props: LogChunkProps) => {
</Typography> </Typography>
</button> </button>
<div <div
className={classes.ChunkBody}
style={{ style={{
backgroundColor: 'white', display: expanded ? 'block' : 'none'
display: expanded ? 'block' : 'none',
overflow: 'hidden'
}} }}
> >
<div id={`log_container`} className={classes.expansionDescription}> <div
id={`log_container`}
className={[styles.expansionDescription, classes.LogContainer].join(
' '
)}
>
<Highlight className={'html'} innerHTML={true}> <Highlight className={'html'} innerHTML={true}>
{expanded ? text : ''} {expanded ? text : ''}
</Highlight> </Highlight>

View File

@@ -1,4 +1,4 @@
import { useEffect, useState, SyntheticEvent } from 'react' import { useEffect, useState } from 'react'
import TreeView from '@mui/lab/TreeView' import TreeView from '@mui/lab/TreeView'
import TreeItem from '@mui/lab/TreeItem' import TreeItem from '@mui/lab/TreeItem'
import { ChevronRight, ExpandMore } from '@mui/icons-material' import { ChevronRight, ExpandMore } from '@mui/icons-material'
@@ -8,28 +8,12 @@ import { makeStyles } from '@mui/styles'
import Highlight from 'react-highlight' import Highlight from 'react-highlight'
import { LogObject, defaultChunkSize } from '../../../../../utils' import { LogObject, defaultChunkSize } from '../../../../../utils'
import { RunTimeType } from '../../../../../context/appContext' import { RunTimeType } from '../../../../../context/appContext'
import { import { splitIntoChunks, LogInstance } from '../../../../../utils'
splitIntoChunks,
LogInstance,
clearErrorsAndWarningsHtmlWrapping,
download
} from '../../../../../utils'
import LogChunk from './logChunk' import LogChunk from './logChunk'
import FileDownloadIcon from '@mui/icons-material/FileDownload' import classes from './log.module.css'
import { Button } from '@mui/material'
const useStyles: any = makeStyles((theme: any) => ({ export const logStyles: any = makeStyles((theme: any) => ({
expansionDescription: { expansionDescription: {
backgroundColor: '#fbfbfb',
border: '1px solid #e2e2e2',
borderRadius: '3px',
minHeight: '50px',
padding: '10px',
boxSizing: 'border-box',
whiteSpace: 'pre-wrap',
fontFamily: 'Monaco, Courier, monospace',
position: 'relative',
width: '100%',
[theme.breakpoints.down('sm')]: { [theme.breakpoints.down('sm')]: {
fontSize: theme.typography.pxToRem(12) fontSize: theme.typography.pxToRem(12)
}, },
@@ -57,7 +41,7 @@ const LogComponent = (props: LogComponentProps) => {
) )
const maxOpenedChunks = 2 const maxOpenedChunks = 2
const classes = useStyles() const styles = logStyles()
const goToLogLine = (logInstance: LogInstance, ind: number) => { const goToLogLine = (logInstance: LogInstance, ind: number) => {
let chunkNumber = 0 let chunkNumber = 0
@@ -145,26 +129,13 @@ const LogComponent = (props: LogComponentProps) => {
return ( return (
<> <>
{selectedRunTime === RunTimeType.SAS && logObject.body ? ( {selectedRunTime === RunTimeType.SAS && logObject.body ? (
<div <div id="logWrapper" className={classes.LogWrapper}>
id="logWrapper" <div>
style={{ overflowY: 'auto', maxHeight: 'calc(100vh - 130px)' }}
>
<div style={{ backgroundColor: 'white' }}>
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 10
}}
></div>
{hasErrorsOrWarnings && ( {hasErrorsOrWarnings && (
<div> <div className={classes.TreeContainer}>
<TreeView <TreeView
defaultCollapseIcon={<ExpandMore />} defaultCollapseIcon={<ExpandMore />}
defaultExpandIcon={<ChevronRight />} defaultExpandIcon={<ChevronRight />}
style={{ paddingBottom: 10 }}
> >
{logObject.errors && logObject.errors.length !== 0 && ( {logObject.errors && logObject.errors.length !== 0 && (
<TreeItem <TreeItem
@@ -208,8 +179,7 @@ const LogComponent = (props: LogComponentProps) => {
</div> </div>
)} )}
</div> </div>
<div className={classes.ChunksContainer}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
{Array.isArray(logChunks) ? ( {Array.isArray(logChunks) ? (
logChunks.map((chunk: string, id: number) => ( logChunks.map((chunk: string, id: number) => (
<LogChunk <LogChunk
@@ -245,7 +215,10 @@ const LogComponent = (props: LogComponentProps) => {
<Typography <Typography
id={`log_container`} id={`log_container`}
variant="h5" variant="h5"
className={classes.expansionDescription} className={[
styles.expansionDescription,
classes.LogContainer
].join(' ')}
> >
<Highlight className={'html'} innerHTML={true}> <Highlight className={'html'} innerHTML={true}>
{logChunks} {logChunks}
@@ -257,10 +230,7 @@ const LogComponent = (props: LogComponentProps) => {
) : ( ) : (
<div> <div>
<h2>Log</h2> <h2>Log</h2>
<pre <pre id="log" className={classes.LogBody}>
id="log"
style={{ overflow: 'auto', height: 'calc(100vh - 220px)' }}
>
{logBody} {logBody}
</pre> </pre>
</div> </div>

View File

@@ -6,6 +6,7 @@ import {
clearErrorsAndWarningsHtmlWrapping clearErrorsAndWarningsHtmlWrapping
} from '../../../../../utils' } from '../../../../../utils'
import Tooltip from '@mui/material/Tooltip' import Tooltip from '@mui/material/Tooltip'
import classes from './log.module.css'
interface LogTabProps { interface LogTabProps {
log: LogObject log: LogObject
@@ -15,28 +16,23 @@ const LogTabWithIcons = (props: LogTabProps) => {
const { errors, warnings, body } = props.log const { errors, warnings, body } = props.log
return ( return (
<div <div className={classes.TabContainer}>
style={{
display: 'flex',
flexDirection: 'row',
gap: 6,
alignItems: 'center'
}}
>
<span>log</span> <span>log</span>
{errors && errors.length !== 0 && ( {errors && errors.length !== 0 && (
<ErrorOutline color="error" style={{ fontSize: 20 }} /> <ErrorOutline color="error" className={classes.Icon} />
)} )}
{warnings && warnings.length !== 0 && ( {warnings && warnings.length !== 0 && (
<Warning style={{ fontSize: 20, color: 'green' }} /> <Warning className={[classes.Icon, classes.GreenIcon].join(' ')} />
)}{' '} )}
<Tooltip <Tooltip
title="Download entire log" title="Download entire log"
onClick={(evt) => { onClick={(evt) => {
download(evt, clearErrorsAndWarningsHtmlWrapping(body)) download(evt, clearErrorsAndWarningsHtmlWrapping(body))
}} }}
> >
<FileDownloadIcon style={{ fontSize: 20, marginLeft: 20 }} /> <FileDownloadIcon
className={[classes.Icon, classes.TabDownloadIcon].join(' ')}
/>
</Tooltip> </Tooltip>
</div> </div>
) )

4
web/src/types/declaration.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module '*.module.css' {
const classes: { [key: string]: string }
export default classes
}

View File

@@ -14,7 +14,8 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,
"jsx": "react-jsx" "jsx": "react-jsx",
"plugins": [{ "name": "typescript-plugin-css-modules" }]
}, },
"include": ["src"] "include": ["src"]
} }

View File

@@ -32,9 +32,18 @@ const config: Configuration = {
] ]
}, },
{ {
test: /\.css$/, test: /\.css$/i,
exclude: ['/node_modules/'], use: [
use: ['style-loader', 'css-loader'] 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]--[hash:base64:5]'
}
}
}
]
}, },
{ {
test: /\.scss$/, test: /\.scss$/,