diff --git a/client/.env b/client/.env index 69d1f92..8a650d5 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.3.5 \ No newline at end of file +REACT_APP_VERSION=1.3.6 \ No newline at end of file diff --git a/client/src/components/Apps/AppTable/AppTable.module.css b/client/src/components/Apps/AppTable/AppTable.module.css index ee9c9a8..8b1e0ed 100644 --- a/client/src/components/Apps/AppTable/AppTable.module.css +++ b/client/src/components/Apps/AppTable/AppTable.module.css @@ -20,10 +20,10 @@ margin-bottom: 20px; } -.Message span { +.Message a { color: var(--color-accent); } -.Message span:hover { +.Message a:hover { cursor: pointer; } \ No newline at end of file diff --git a/client/src/components/Apps/AppTable/AppTable.tsx b/client/src/components/Apps/AppTable/AppTable.tsx index 1d80477..6ef6e6c 100644 --- a/client/src/components/Apps/AppTable/AppTable.tsx +++ b/client/src/components/Apps/AppTable/AppTable.tsx @@ -1,22 +1,52 @@ -import { KeyboardEvent } from 'react'; -import { connect } from 'react-redux'; -import { App, GlobalState } from '../../../interfaces'; -import { pinApp, deleteApp, reorderApp } from '../../../store/actions'; +import { Fragment, KeyboardEvent, useState, useEffect } from 'react'; import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd'; +import { Link } from 'react-router-dom'; +// Redux +import { connect } from 'react-redux'; +import { pinApp, deleteApp, reorderApps, updateConfig, createNotification } from '../../../store/actions'; + +// Typescript +import { App, GlobalState, NewNotification } from '../../../interfaces'; + +// CSS import classes from './AppTable.module.css'; + +// UI import Icon from '../../UI/Icons/Icon/Icon'; import Table from '../../UI/Table/Table'; +// Utils +import { searchConfig } from '../../../utility'; + interface ComponentProps { apps: App[]; pinApp: (app: App) => void; deleteApp: (id: number) => void; updateAppHandler: (app: App) => void; - reorderApp: (apps: App[]) => void; + reorderApps: (apps: App[]) => void; + updateConfig: (formData: any) => void; + createNotification: (notification: NewNotification) => void; } const AppTable = (props: ComponentProps): JSX.Element => { + const [localApps, setLocalApps] = useState([]); + const [isCustomOrder, setIsCustomOrder] = useState(false); + + // Copy apps array + useEffect(() => { + setLocalApps([...props.apps]); + }, [props.apps]) + + // Check ordering + useEffect(() => { + const order = searchConfig('useOrdering', ''); + + if (order === 'orderId') { + setIsCustomOrder(true); + } + }, []) + const deleteAppHandler = (app: App): void => { const proceed = window.confirm(`Are you sure you want to delete ${app.name} at ${app.url} ?`); @@ -25,6 +55,7 @@ const AppTable = (props: ComponentProps): JSX.Element => { } } + // Support keyboard navigation for actions const keyboardActionHandler = (e: KeyboardEvent, app: App, handler: Function) => { if (e.key === 'Enter') { handler(app); @@ -32,88 +63,103 @@ const AppTable = (props: ComponentProps): JSX.Element => { } const dragEndHanlder = (result: DropResult): void => { - console.log(result); + if (!isCustomOrder) { + props.createNotification({ + title: 'Error', + message: 'Custom order is disabled' + }) + return; + } if (!result.destination) { return; } - const tmpApps = [...props.apps]; + const tmpApps = [...localApps]; const [movedApp] = tmpApps.splice(result.source.index, 1); tmpApps.splice(result.destination.index, 0, movedApp); - props.reorderApp(tmpApps); + setLocalApps(tmpApps); + props.reorderApps(tmpApps); } return ( - - - {(provided) => ( - - {props.apps.map((app: App, index): JSX.Element => { - return ( - - {(provided, snapshot) => { - const style = { - border: snapshot.isDragging ? '1px solid var(--color-accent)' : 'none', - borderRadius: '4px', - ...provided.draggableProps.style, - }; + +
+ {isCustomOrder + ?

You can drag and drop single rows to reorder application

+ :

Custom order is disabled. You can change it in settings

+ } +
+ + + {(provided) => ( +
+ {localApps.map((app: App, index): JSX.Element => { + return ( + + {(provided, snapshot) => { + const style = { + border: snapshot.isDragging ? '1px solid var(--color-accent)' : 'none', + borderRadius: '4px', + ...provided.draggableProps.style, + }; - return ( - - - - - {!snapshot.isDragging && ( - - )} - - ) - }} - - ) - })} -
{app.name}{app.url}{app.icon} -
deleteAppHandler(app)} - onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)} - tabIndex={0}> - -
-
props.updateAppHandler(app)} - onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)} - tabIndex={0}> - -
-
props.pinApp(app)} - onKeyDown={(e) => keyboardActionHandler(e, app, props.pinApp)} - tabIndex={0}> - {app.isPinned - ? - : - } -
-
- )} -
-
+ return ( + + {app.name} + {app.url} + {app.icon} + {!snapshot.isDragging && ( + +
deleteAppHandler(app)} + onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)} + tabIndex={0}> + +
+
props.updateAppHandler(app)} + onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)} + tabIndex={0}> + +
+
props.pinApp(app)} + onKeyDown={(e) => keyboardActionHandler(e, app, props.pinApp)} + tabIndex={0}> + {app.isPinned + ? + : + } +
+ + )} + + ) + }} + + ) + })} + + )} + + + ) } @@ -123,4 +169,12 @@ const mapStateToProps = (state: GlobalState) => { } } -export default connect(mapStateToProps, { pinApp, deleteApp, reorderApp })(AppTable); \ No newline at end of file +const actions = { + pinApp, + deleteApp, + reorderApps, + updateConfig, + createNotification +} + +export default connect(mapStateToProps, actions)(AppTable); \ No newline at end of file diff --git a/client/src/store/actions/app.ts b/client/src/store/actions/app.ts index 8dc9e94..ebd66ad 100644 --- a/client/src/store/actions/app.ts +++ b/client/src/store/actions/app.ts @@ -161,15 +161,7 @@ export const reorderApps = (apps: App[]) => async (dispatch: Dispatch) => { orderId: index + 1 })) - await axios.put<{}>('/api/apps/0/reorder', updateQuery); - - dispatch({ - type: ActionTypes.createNotification, - payload: { - title: 'Success', - message: 'New order saved' - } - }) + await axios.put>('/api/apps/0/reorder', updateQuery); dispatch({ type: ActionTypes.reorderApps, @@ -189,8 +181,6 @@ export const sortApps = () => async (dispatch: Dispatch) => { try { const res = await axios.get>('/api/config/useOrdering'); - console.log(res.data.data); - dispatch({ type: ActionTypes.sortApps, payload: res.data.data.value