Skip to content

Commit

Permalink
wip: refactor visibility header buttons to avoid duplication
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Oct 13, 2024
1 parent 2284e1c commit aa1f26b
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 164 deletions.
68 changes: 68 additions & 0 deletions webui/src/Components/TableVisibility.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { CButton } from '@coreui/react'
import classNames from 'classnames'
import { cloneDeep } from 'lodash-es'
import React from 'react'
import { useCallback, useEffect, useState } from 'react'

export interface TableVisibilityHelper<T extends Record<string, boolean>> {
visiblity: T
toggleVisibility: (key: keyof T) => void
}

export function useTableVisibilityHelper<T extends Record<string, any>>(
localStorageKey: string,
defaultValue: T
): TableVisibilityHelper<T> {
const [visiblity, setVisibility] = useState<T>(() => {
try {
const rawConfig = window.localStorage.getItem(localStorageKey)
if (rawConfig !== null) {
return JSON.parse(rawConfig) ?? {}
}
} catch (e) {}

// setup defaults
window.localStorage.setItem(localStorageKey, JSON.stringify(defaultValue))

return cloneDeep(defaultValue)
})

const toggleVisibility = useCallback((key: keyof T) => {
setVisibility((oldConfig) => ({
...oldConfig,
[key]: !oldConfig[key],
}))
}, [])

// Save the config when it changes
useEffect(() => {
window.localStorage.setItem(localStorageKey, JSON.stringify(visiblity))
}, [localStorageKey, visiblity])

return {
visiblity,
toggleVisibility,
}
}

interface VisibilityButtonProps<T extends Record<string, boolean>> extends TableVisibilityHelper<T> {
keyId: keyof T
color: string
label: string
}

export function VisibilityButton<T extends Record<string, any>>({
keyId,
color,
label,
visiblity,
toggleVisibility,
}: VisibilityButtonProps<T>) {
const doToggle = useCallback(() => toggleVisibility(keyId), [keyId, toggleVisibility])

return (
<CButton size="sm" color={color} className={classNames({ active: visiblity[keyId] })} onClick={doToggle}>
{label}
</CButton>
)
}
100 changes: 17 additions & 83 deletions webui/src/Connections/ConnectionList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { RefObject, useCallback, useContext, useEffect, useRef, useState } from 'react'
import React, { RefObject, useCallback, useContext, useEffect, useRef } from 'react'
import { CButton, CButtonGroup, CFormSwitch, CPopover } from '@coreui/react'
import { ConnectionsContext, socketEmitPromise, SocketContext } from '../util.js'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
Expand All @@ -15,7 +15,6 @@ import {
faEllipsisV,
faPlug,
} from '@fortawesome/free-solid-svg-icons'

import { ConnectionVariablesModal, ConnectionVariablesModalRef } from './ConnectionVariablesModal.js'
import { GenericConfirmModal, GenericConfirmModalRef } from '../Components/GenericConfirmModal.js'
import { useDrag, useDrop } from 'react-dnd'
Expand All @@ -28,6 +27,7 @@ import { NonIdealState } from '../Components/NonIdealState.js'
import { Tuck } from '../Components/Tuck.js'
import { NewClientModuleVersionInfo2 } from '@companion-app/shared/Model/ModuleInfo.js'
import { getModuleVersionInfoForConnection } from './Util.js'
import { useTableVisibilityHelper, VisibilityButton } from '../Components/TableVisibility.js'

interface VisibleConnectionsState {
disabled: boolean
Expand Down Expand Up @@ -64,24 +64,12 @@ export function ConnectionsList({
variablesModalRef.current?.show(connectionId)
}, [])

const [visibleConnections, setVisibleConnections] = useState<VisibleConnectionsState>(() => loadVisibility())

// Save the config when it changes
useEffect(() => {
window.localStorage.setItem('connections_visible', JSON.stringify(visibleConnections))
}, [visibleConnections])

const doToggleVisibility = useCallback((key: keyof VisibleConnectionsState) => {
setVisibleConnections((oldConfig) => ({
...oldConfig,
[key]: !oldConfig[key],
}))
}, [])

const doToggleDisabled = useCallback(() => doToggleVisibility('disabled'), [doToggleVisibility])
const doToggleOk = useCallback(() => doToggleVisibility('ok'), [doToggleVisibility])
const doToggleWarning = useCallback(() => doToggleVisibility('warning'), [doToggleVisibility])
const doToggleError = useCallback(() => doToggleVisibility('error'), [doToggleVisibility])
const visibleConnections = useTableVisibilityHelper<VisibleConnectionsState>('connections_visible', {
disabled: true,
ok: true,
warning: true,
error: true,
})

const moveRow = useCallback(
(itemId: string, targetId: string) => {
Expand Down Expand Up @@ -112,14 +100,14 @@ export function ConnectionsList({
.map(([id, connection]) => {
const status = connectionStatus?.[id]

if (!visibleConnections.disabled && connection.enabled === false) {
if (!visibleConnections.visiblity.disabled && connection.enabled === false) {
return undefined
} else if (status) {
if (!visibleConnections.ok && status.category === 'good') {
if (!visibleConnections.visiblity.ok && status.category === 'good') {
return undefined
} else if (!visibleConnections.warning && status.category === 'warning') {
} else if (!visibleConnections.visiblity.warning && status.category === 'warning') {
return undefined
} else if (!visibleConnections.error && status.category === 'error') {
} else if (!visibleConnections.visiblity.error && status.category === 'error') {
return undefined
}
}
Expand Down Expand Up @@ -162,44 +150,11 @@ export function ConnectionsList({
<th>Label</th>
<th>Module</th>
<th colSpan={3} className="fit">
<CButtonGroup style={{ float: 'right', margin: 0 }}>
<CButton
size="sm"
color="secondary"
style={{
backgroundColor: 'white',
opacity: visibleConnections.disabled ? 1 : 0.4,
padding: '1px 5px',
color: 'black',
}}
onClick={doToggleDisabled}
>
Disabled
</CButton>
<CButton
size="sm"
color="success"
style={{ opacity: visibleConnections.ok ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleOk}
>
OK
</CButton>
<CButton
color="warning"
size="sm"
style={{ opacity: visibleConnections.warning ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleWarning}
>
Warning
</CButton>
<CButton
color="danger"
size="sm"
style={{ opacity: visibleConnections.error ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleError}
>
Error
</CButton>
<CButtonGroup className="table-header-buttons">
<VisibilityButton {...visibleConnections} keyId="disabled" color="secondary" label="Disabled" />
<VisibilityButton {...visibleConnections} keyId="ok" color="success" label="OK" />
<VisibilityButton {...visibleConnections} keyId="warning" color="warning" label="Warning" />
<VisibilityButton {...visibleConnections} keyId="error" color="danger" label="Error" />
</CButtonGroup>
</th>
</tr>
Expand Down Expand Up @@ -231,27 +186,6 @@ export function ConnectionsList({
)
}

function loadVisibility(): VisibleConnectionsState {
try {
const rawConfig = window.localStorage.getItem('connections_visible')
if (rawConfig !== null) {
return JSON.parse(rawConfig) ?? {}
}
} catch (e) {}

// setup defaults
const config: VisibleConnectionsState = {
disabled: true,
ok: true,
warning: true,
error: true,
}

window.localStorage.setItem('connections_visible', JSON.stringify(config))

return config
}

interface ConnectionDragItem {
id: string
}
Expand Down
97 changes: 16 additions & 81 deletions webui/src/Modules/ModulesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { NewClientModuleVersionInfo2 } from '@companion-app/shared/Model/ModuleI
import { SearchBox } from '../Components/SearchBox.js'
import { ModuleProductInfo, useFilteredProducts } from '../Hooks/useFilteredProducts.js'
import { ImportCustomModule } from './ImportCustomModule.js'
import { useTableVisibilityHelper, VisibilityButton } from '../Components/TableVisibility.js'

interface VisibleModulesState {
dev: boolean
Expand Down Expand Up @@ -41,24 +42,12 @@ export const ModulesList = observer(function ModulesList({
connectionsRef.current = connectionsContext
}, [connectionsContext])

const [visibleModules, setVisibleModules] = useState<VisibleModulesState>(() => loadVisibility())

// Save the config when it changes
useEffect(() => {
window.localStorage.setItem('modules_visible', JSON.stringify(visibleModules))
}, [visibleModules])

const doToggleVisibility = useCallback((key: keyof VisibleModulesState) => {
setVisibleModules((oldConfig) => ({
...oldConfig,
[key]: !oldConfig[key],
}))
}, [])

const doToggleDev = useCallback(() => doToggleVisibility('dev'), [doToggleVisibility])
const doToggleBuiltin = useCallback(() => doToggleVisibility('builtin'), [doToggleVisibility])
const doToggleStore = useCallback(() => doToggleVisibility('store'), [doToggleVisibility])
const doToggleCustom = useCallback(() => doToggleVisibility('custom'), [doToggleVisibility])
const visibleModules = useTableVisibilityHelper<VisibleModulesState>('modules_visible', {
dev: true,
builtin: true,
store: true,
custom: true,
})

const [filter, setFilter] = useState('')

Expand All @@ -69,8 +58,8 @@ export const ModulesList = observer(function ModulesList({
const candidatesObj: Record<string, JSX.Element> = {}
for (const moduleInfo of searchResults) {
let isVisible = false
if (moduleInfo.hasDevVersion && visibleModules.dev) isVisible = true
if (moduleInfo.customVersions.length && visibleModules.custom) isVisible = true
if (moduleInfo.hasDevVersion && visibleModules.visiblity.dev) isVisible = true
if (moduleInfo.customVersions.length && visibleModules.visiblity.custom) isVisible = true

const [hasBuiltin, hasStore] = moduleInfo.releaseVersions.reduce(
([builtin, release], v) => {
Expand All @@ -80,8 +69,8 @@ export const ModulesList = observer(function ModulesList({
},
[false, false]
)
if (hasBuiltin && visibleModules.builtin) isVisible = true
if (hasStore && visibleModules.store) isVisible = true
if (hasBuiltin && visibleModules.visiblity.builtin) isVisible = true
if (hasStore && visibleModules.visiblity.store) isVisible = true

if (!isVisible) continue

Expand Down Expand Up @@ -140,44 +129,11 @@ export const ModulesList = observer(function ModulesList({
<tr>
<th>Module</th>
<th colSpan={3} className="fit">
<CButtonGroup style={{ float: 'right', margin: 0 }}>
<CButton
size="sm"
color="secondary"
style={{
backgroundColor: 'white',
opacity: visibleModules.dev ? 1 : 0.4,
padding: '1px 5px',
color: 'black',
}}
onClick={doToggleDev}
>
Dev
</CButton>
<CButton
size="sm"
color="success"
style={{ opacity: visibleModules.builtin ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleBuiltin}
>
Builtin
</CButton>
<CButton
color="warning"
size="sm"
style={{ opacity: visibleModules.store ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleStore}
>
Store
</CButton>
<CButton
color="danger"
size="sm"
style={{ opacity: visibleModules.custom ? 1 : 0.4, padding: '1px 5px' }}
onClick={doToggleCustom}
>
Custom
</CButton>
<CButtonGroup className="table-header-buttons">
<VisibilityButton {...visibleModules} keyId="dev" color="secondary" label="Dev" />
<VisibilityButton {...visibleModules} keyId="builtin" color="success" label="Builtin" />
<VisibilityButton {...visibleModules} keyId="store" color="warning" label="Store" />
<VisibilityButton {...visibleModules} keyId="custom" color="danger" label="Custom" />
</CButtonGroup>
</th>
</tr>
Expand Down Expand Up @@ -209,27 +165,6 @@ export const ModulesList = observer(function ModulesList({
)
})

function loadVisibility(): VisibleModulesState {
try {
const rawConfig = window.localStorage.getItem('modules_visible')
if (rawConfig !== null) {
return JSON.parse(rawConfig) ?? {}
}
} catch (e) {}

// setup defaults
const config: VisibleModulesState = {
dev: true,
builtin: true,
store: true,
custom: true,
}

window.localStorage.setItem('modules_visible', JSON.stringify(config))

return config
}

interface ModulesListRowProps {
id: string
moduleInfo: ModuleProductInfo
Expand Down
19 changes: 19 additions & 0 deletions webui/src/scss/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ th {
}
}

.table-header-buttons {
float: right;
margin: 0;

button {
padding: 1px 5px;
opacity: 0.4;

&.active {
opacity: 1;
}

&.btn-secondary {
background-color: white;
color: black;
}
}
}

code {
font-family: 'Fira Code', monospace;
font-size: 1.05em;
Expand Down

0 comments on commit aa1f26b

Please sign in to comment.