-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SALAD-23959] WebApp: Reusable Table component - added (#1263)
* Reusable Table component - added * Table: refactor * _AllMachines: getRows - refactor * _AllMachines: checkboxes styles - added * logs - removed * _AllMachines: machines are made selectable * _AllMachines: styles - improved * _AllMachines: warningPill styles - changed * _AllMachines: Machine ID question icon - added * AllMachines - temporary commented * _AllMachines: selectedMachineIds state - refactored
- Loading branch information
Showing
7 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Text } from '@saladtechnologies/garden-components' | ||
import type CSS from 'csstype' | ||
import { type FunctionComponent } from 'react' | ||
import type { WithStyles } from 'react-jss' | ||
import withStyles from 'react-jss' | ||
import type { SaladTheme } from '../../SaladTheme' | ||
import type { TableRow, TableTitles } from './types' | ||
|
||
const styles: (theme: SaladTheme) => Record<string, CSS.Properties> = (theme: SaladTheme) => ({ | ||
tableWrapper: { | ||
fontFamily: theme.fontMallory, | ||
color: theme.lightGreen, | ||
fontSize: '14px', | ||
width: '100%', | ||
'@media (max-width: 900px)': { | ||
overflow: 'scroll', | ||
}, | ||
}, | ||
tableContent: { | ||
overflow: 'hidden', | ||
boxSizing: 'border-box', | ||
}, | ||
table: { | ||
width: '100%', | ||
borderCollapse: 'collapse', | ||
}, | ||
tableHeaderRow: { | ||
borderBottom: `1px #3B4D5C solid`, | ||
}, | ||
tableRow: { | ||
borderBottom: `1px #3B4D5C solid`, | ||
}, | ||
tableCell: {}, | ||
}) | ||
|
||
interface Props extends WithStyles<typeof styles> { | ||
titles: TableTitles | ||
rows: Array<TableRow> | ||
} | ||
|
||
const _Table: FunctionComponent<Props> = ({ classes, titles, rows }) => { | ||
return ( | ||
<div className={classes.tableWrapper}> | ||
<div className={classes.tableContent}> | ||
<table className={classes.table}> | ||
<thead> | ||
<tr className={classes.tableHeaderRow}> | ||
{titles.map((title) => { | ||
const titleJSX = typeof title === 'object' ? title : <Text variant="baseXS">{title}</Text> | ||
return ( | ||
<th className={classes.tableCell} key={title.toString()}> | ||
{titleJSX} | ||
</th> | ||
) | ||
})} | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{rows.map((row, index) => { | ||
return ( | ||
<tr key={index} className={classes.tableRow}> | ||
{row.map((rowItem) => { | ||
const rowItemJSX = | ||
typeof rowItem === 'object' ? rowItem : <Text variant="baseXS">{rowItem.toString()}</Text> | ||
return <td className={classes.tableCell}>{rowItemJSX}</td> | ||
})} | ||
</tr> | ||
) | ||
})} | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export const Table = withStyles(styles)(_Table) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './Table' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export type TableRowItem = string | number | JSX.Element | ||
|
||
export type TableRow = Array<TableRowItem> | ||
|
||
export type TableTitles = Array<JSX.Element | string> |
191 changes: 191 additions & 0 deletions
191
packages/web-app/src/modules/earn-views/components/AllMachines/AllMachines.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import { faCircleQuestion, faList } from '@fortawesome/free-solid-svg-icons' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { Checkbox, Text } from '@saladtechnologies/garden-components' | ||
import classNames from 'classnames' | ||
import type CSS from 'csstype' | ||
import { DateTime } from 'luxon' | ||
import { useState } from 'react' | ||
import type { WithStyles } from 'react-jss' | ||
import withStyles from 'react-jss' | ||
import { Table } from '../../../../components/Table' | ||
import type { TableRow } from '../../../../components/Table/types' | ||
import { DefaultTheme, type SaladTheme } from '../../../../SaladTheme' | ||
import { EarnSectionHeader } from '../EarnSectionHeader' | ||
import { generatedMockedMachines } from './mocks' | ||
|
||
const styles: (theme: SaladTheme) => Record<string, CSS.Properties> = (theme: SaladTheme) => ({ | ||
allMachinesWrapper: { | ||
display: 'flex', | ||
justifyContent: 'flex-start', | ||
alignItems: 'flex-start', | ||
flexDirection: 'column', | ||
width: '100%', | ||
position: 'relative', | ||
}, | ||
tableWrapper: { | ||
display: 'flex', | ||
flexDirection: 'column', | ||
flex: 1, | ||
position: 'relative', | ||
height: '200px', | ||
width: '100%', | ||
maxWidth: '700px', | ||
}, | ||
tableCell: { | ||
padding: '4px', | ||
fontSize: '14px', | ||
}, | ||
tableHeaderCell: { | ||
padding: '10px', | ||
paddingLeft: '0px', | ||
display: 'flex', | ||
justifyContent: 'flex-start', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
}, | ||
tableCellCentered: { | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
}, | ||
warningPillWrapper: { | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
gap: '6px', | ||
}, | ||
warningPill: { | ||
height: '23px', | ||
padding: '0px 8px', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
borderRadius: '16px', | ||
backgroundColor: '#F6931D', | ||
width: 'auto', | ||
color: theme.darkBlue, | ||
textDecoration: 'underline', | ||
}, | ||
checkboxWrapper: { | ||
width: '22px', | ||
height: '22px', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
border: `1px ${theme.lightGreen} solid`, | ||
transform: 'scale(0.8)', | ||
}, | ||
questionIconWrapper: { | ||
marginLeft: '6px', | ||
backgroundColor: theme.lightGreen, | ||
border: `.5px solid ${theme.lightGreen}`, | ||
borderRadius: '100%', | ||
width: '13px', | ||
height: '13px', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'row', | ||
cursor: 'pointer', | ||
}, | ||
}) | ||
|
||
interface Props extends WithStyles<typeof styles> {} | ||
|
||
const _AllMachines = ({ classes }: Props) => { | ||
const [selectedMachineIds, setSelectedMachineIds] = useState<Record<string, boolean>>(() => | ||
Object.fromEntries(generatedMockedMachines.map((machine) => [machine.id, false])), | ||
) | ||
|
||
const handleMachineIdQuestionIconClick = () => { | ||
window.location.href = 'https://support.salad.com/article/414-how-to-find-your-salad-machine-id' | ||
} | ||
|
||
const getTitles = () => { | ||
return [ | ||
<div className={(classes.tableHeaderCell, classes.tableCellCentered)}> | ||
<FontAwesomeIcon icon={faList} /> | ||
</div>, | ||
<div className={classes.tableHeaderCell}> | ||
<Text variant="baseXS">Machine ID</Text> | ||
<div className={classes.questionIconWrapper} onClick={handleMachineIdQuestionIconClick}> | ||
<FontAwesomeIcon | ||
size="sm" | ||
icon={faCircleQuestion} | ||
fill={DefaultTheme.darkBlue} | ||
color={DefaultTheme.darkBlue} | ||
/> | ||
</div> | ||
</div>, | ||
<div className={classes.tableHeaderCell}> | ||
<Text variant="baseXS">Running Status</Text> | ||
</div>, | ||
<div className={classes.tableHeaderCell}> | ||
<Text variant="baseXS">Last Seen</Text> | ||
</div>, | ||
<div className={classNames(classes.tableHeaderCell, classes.tableCellCentered)}> | ||
<Text variant="baseXS">Current Earning Rate</Text> | ||
</div>, | ||
<div className={classNames(classes.tableHeaderCell, classes.tableCellCentered)}> | ||
<Text variant="baseXS">Warnings</Text> | ||
</div>, | ||
] | ||
} | ||
|
||
const getRows = (): Array<TableRow> => { | ||
return generatedMockedMachines | ||
.map((machine) => { | ||
return { | ||
checkbox: ( | ||
<div className={classNames(classes.tableCell, classes.tableCellCentered)}> | ||
<div className={classes.checkboxWrapper}> | ||
<Checkbox | ||
onChange={(checked) => | ||
setSelectedMachineIds((previousSelectedMachineIds) => ({ | ||
...previousSelectedMachineIds, | ||
[machine.id]: checked, | ||
})) | ||
} | ||
checked={selectedMachineIds[machine.id]} | ||
/> | ||
</div> | ||
</div> | ||
), | ||
...machine, | ||
lastSeen: DateTime.fromJSDate(machine.lastSeen).toFormat('MMM d, yyyy'), | ||
currentEarningRate: ( | ||
<div className={classNames(classes.tableCell, classes.tableCellCentered)}>{machine.currentEarningRate}</div> | ||
), | ||
warnings: ( | ||
<div className={classes.warningPillWrapper}> | ||
{machine.warnings.map((warningText) => ( | ||
<div className={classes.warningPill}> | ||
<Text variant="baseXS">{warningText}</Text> | ||
</div> | ||
))} | ||
</div> | ||
), | ||
} | ||
}) | ||
.map((machineRow) => | ||
Object.values(machineRow).map((machineRowItem) => { | ||
return <div className={classes.tableCell}>{machineRowItem}</div> | ||
}), | ||
) | ||
} | ||
|
||
return ( | ||
<div className={classes.allMachinesWrapper}> | ||
<EarnSectionHeader>All Machines</EarnSectionHeader> | ||
<div className={classes.tableWrapper}> | ||
<Table titles={getTitles()} rows={getRows()} /> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export const AllMachines = withStyles(styles)(_AllMachines) |
1 change: 1 addition & 0 deletions
1
packages/web-app/src/modules/earn-views/components/AllMachines/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './AllMachines' |
80 changes: 80 additions & 0 deletions
80
packages/web-app/src/modules/earn-views/components/AllMachines/mocks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
export interface MachineState { | ||
id: string | ||
status: RunningStatus | ||
lastSeen: Date | ||
currentEarningRate: number | ||
warnings: MachineWarnings[] | ||
} | ||
|
||
type RunningStatus = 'Idle' | 'Offline' | 'Downloading Job' | 'Downloading Job' | 'Running Job' | ||
type MachineWarnings = 'Idle' | 'Wsl Update' | 'Network Blocked' | ||
|
||
export const getRandomId = (): string => { | ||
let text: string = '' | ||
const possible: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' | ||
|
||
for (let i = 0; i < 6; i++) { | ||
text += possible.charAt(Math.floor(Math.random() * possible.length)) | ||
} | ||
|
||
return text | ||
} | ||
|
||
const generateMockedMachines = () => { | ||
return Array(100) | ||
.fill(null) | ||
.map(() => ({ | ||
id: getRandomId().toLocaleLowerCase(), | ||
status: 'Idle', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked'], | ||
})) | ||
} | ||
|
||
export const generatedMockedMachines = generateMockedMachines() | ||
|
||
export const mockedMachines: MachineState[] = [ | ||
{ | ||
id: '0', | ||
status: 'Idle', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked'], | ||
}, | ||
{ | ||
id: '1', | ||
status: 'Offline', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: [], | ||
}, | ||
{ | ||
id: '2', | ||
status: 'Running Job', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked', 'Idle'], | ||
}, | ||
{ | ||
id: '3', | ||
status: 'Downloading Job', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked', 'Idle'], | ||
}, | ||
{ | ||
id: '4', | ||
status: 'Downloading Job', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked', 'Idle'], | ||
}, | ||
{ | ||
id: '5', | ||
status: 'Downloading Job', | ||
lastSeen: new Date(), | ||
currentEarningRate: 0.018, | ||
warnings: ['Wsl Update', 'Network Blocked', 'Idle'], | ||
}, | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters