From 49eece97f7974b3ab74fc1974e46c502df0a25fe Mon Sep 17 00:00:00 2001 From: Ken Hibino Date: Sat, 26 Feb 2022 16:43:58 -0800 Subject: [PATCH] (ui): Hide action buttons in read-only mode --- ui/public/index.html | 1 + ui/src/components/ActiveTasksTable.tsx | 161 +++++++------- ui/src/components/ArchivedTasksTable.tsx | 203 +++++++++--------- ui/src/components/CompletedTasksTable.tsx | 161 +++++++------- ui/src/components/PendingTasksTable.tsx | 209 +++++++++--------- ui/src/components/QueuesOverviewTable.tsx | 129 ++++++------ ui/src/components/RetryTasksTable.tsx | 245 ++++++++++++---------- ui/src/components/ScheduledTasksTable.tsx | 245 ++++++++++++---------- ui/src/global.d.ts | 3 + 9 files changed, 723 insertions(+), 634 deletions(-) diff --git a/ui/public/index.html b/ui/public/index.html index da8bbda..90c3dbc 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -52,6 +52,7 @@ Asynq - Monitoring diff --git a/ui/src/components/ActiveTasksTable.tsx b/ui/src/components/ActiveTasksTable.tsx index 83c852d..2668234 100644 --- a/ui/src/components/ActiveTasksTable.tsx +++ b/ui/src/components/ActiveTasksTable.tsx @@ -161,24 +161,26 @@ function ActiveTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Cancel", - icon: , - onClick: handleBatchCancelClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Cancel All", - onClick: handleCancelAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Cancel", + icon: , + onClick: handleBatchCancelClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Cancel All", + onClick: handleCancelAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )} - - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -311,16 +320,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -364,32 +375,34 @@ function Row(props: RowProps) { {task.deadline === "-" ? "-" : durationBefore(task.deadline)} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/components/ArchivedTasksTable.tsx b/ui/src/components/ArchivedTasksTable.tsx index 9fcf546..dabf647 100644 --- a/ui/src/components/ArchivedTasksTable.tsx +++ b/ui/src/components/ArchivedTasksTable.tsx @@ -180,35 +180,37 @@ function ArchivedTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Delete", - icon: , - onClick: handleBatchDeleteClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Run", - icon: , - onClick: handleBatchRunClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Delete All", - onClick: handleDeleteAllClick, - disabled: props.allActionPending, - }, - { - label: "Run All", - onClick: handleRunAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Delete", + icon: , + onClick: handleBatchDeleteClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Run", + icon: , + onClick: handleBatchRunClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Delete All", + onClick: handleDeleteAllClick, + disabled: props.allActionPending, + }, + { + label: "Run All", + onClick: handleRunAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )}
- - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -353,16 +362,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -391,42 +402,44 @@ function Row(props: RowProps) { {timeAgo(task.last_failed_at)} {task.error_message} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/components/CompletedTasksTable.tsx b/ui/src/components/CompletedTasksTable.tsx index c69f40a..bc4dac1 100644 --- a/ui/src/components/CompletedTasksTable.tsx +++ b/ui/src/components/CompletedTasksTable.tsx @@ -167,24 +167,26 @@ function CompletedTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Delete", - icon: , - onClick: handleBatchDeleteClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Delete All", - onClick: handleDeleteAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Delete", + icon: , + onClick: handleBatchDeleteClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Delete All", + onClick: handleDeleteAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )}
- - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -328,16 +337,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -378,32 +389,34 @@ function Row(props: RowProps) { ? `${stringifyDuration(durationFromSeconds(task.ttl_seconds))} left` : `expired`} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/components/PendingTasksTable.tsx b/ui/src/components/PendingTasksTable.tsx index c8a824d..c057e84 100644 --- a/ui/src/components/PendingTasksTable.tsx +++ b/ui/src/components/PendingTasksTable.tsx @@ -176,35 +176,37 @@ function PendingTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Delete", - icon: , - onClick: handleBatchDeleteClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Archive", - icon: , - onClick: handleBatchArchiveClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Delete All", - onClick: handleDeleteAllClick, - disabled: props.allActionPending, - }, - { - label: "Archive All", - onClick: handleArchiveAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Delete", + icon: , + onClick: handleBatchDeleteClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Archive", + icon: , + onClick: handleBatchArchiveClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Delete All", + onClick: handleDeleteAllClick, + disabled: props.allActionPending, + }, + { + label: "Archive All", + onClick: handleArchiveAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )}
- - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -355,16 +364,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -393,42 +404,44 @@ function Row(props: RowProps) { {task.retried} {task.max_retry} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/components/QueuesOverviewTable.tsx b/ui/src/components/QueuesOverviewTable.tsx index b725bf8..53ed3c5 100644 --- a/ui/src/components/QueuesOverviewTable.tsx +++ b/ui/src/components/QueuesOverviewTable.tsx @@ -183,25 +183,30 @@ export default function QueuesOverviewTable(props: Props) {
- {colConfigs.map((cfg, i) => ( - - {cfg.sortBy !== SortBy.None ? ( - - {cfg.label} - - ) : ( -
{cfg.label}
- )} -
- ))} + {colConfigs + .filter((cfg) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || cfg.key !== "actions"; + }) + .map((cfg, i) => ( + + {cfg.sortBy !== SortBy.None ? ( + + {cfg.label} + + ) : ( +
{cfg.label}
+ )} +
+ ))}
@@ -298,50 +303,52 @@ function Row(props: RowProps) { {q.processed} {q.failed} {percentage(q.failed, q.processed)} - setShowIcons(true)} - onMouseLeave={() => setShowIcons(false)} - > -
- {showIcons ? ( - - {q.paused ? ( - - - + {!window.READ_ONLY && ( + setShowIcons(true)} + onMouseLeave={() => setShowIcons(false)} + > +
+ {showIcons ? ( + + {q.paused ? ( + + + + + + ) : ( + + + + + + )} + + + - ) : ( - - - - - - )} - - - - - - - ) : ( - - - - )} -
-
+
+ ) : ( + + + + )} +
+
+ )} ); } diff --git a/ui/src/components/RetryTasksTable.tsx b/ui/src/components/RetryTasksTable.tsx index f14ae1e..5eeb21c 100644 --- a/ui/src/components/RetryTasksTable.tsx +++ b/ui/src/components/RetryTasksTable.tsx @@ -196,46 +196,48 @@ function RetryTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Delete", - icon: , - onClick: handleBatchDeleteClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Archive", - icon: , - onClick: handleBatchArchiveClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Run", - icon: , - onClick: handleBatchRunClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Delete All", - onClick: handleDeleteAllClick, - disabled: props.allActionPending, - }, - { - label: "Archive All", - onClick: handleArchiveAllClick, - disabled: props.allActionPending, - }, - { - label: "Run All", - onClick: handleRunAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Delete", + icon: , + onClick: handleBatchDeleteClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Archive", + icon: , + onClick: handleBatchArchiveClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Run", + icon: , + onClick: handleBatchRunClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Delete All", + onClick: handleDeleteAllClick, + disabled: props.allActionPending, + }, + { + label: "Archive All", + onClick: handleArchiveAllClick, + disabled: props.allActionPending, + }, + { + label: "Run All", + onClick: handleRunAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )}
- - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -388,16 +397,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -428,52 +439,54 @@ function Row(props: RowProps) { {task.error_message} {task.retried} {task.max_retry} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - - - - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + + + + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/components/ScheduledTasksTable.tsx b/ui/src/components/ScheduledTasksTable.tsx index 1585035..db4cb01 100644 --- a/ui/src/components/ScheduledTasksTable.tsx +++ b/ui/src/components/ScheduledTasksTable.tsx @@ -193,46 +193,48 @@ function ScheduledTasksTable(props: Props & ReduxProps) { const numSelected = selectedIds.length; return (
- 0} - iconButtonActions={[ - { - tooltip: "Delete", - icon: , - onClick: handleBatchDeleteClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Archive", - icon: , - onClick: handleBatchArchiveClick, - disabled: props.batchActionPending, - }, - { - tooltip: "Run", - icon: , - onClick: handleBatchRunClick, - disabled: props.batchActionPending, - }, - ]} - menuItemActions={[ - { - label: "Delete All", - onClick: handleDeleteAllClick, - disabled: props.allActionPending, - }, - { - label: "Archive All", - onClick: handleArchiveAllClick, - disabled: props.allActionPending, - }, - { - label: "Run All", - onClick: handleRunAllClick, - disabled: props.allActionPending, - }, - ]} - /> + {!window.READ_ONLY && ( + 0} + iconButtonActions={[ + { + tooltip: "Delete", + icon: , + onClick: handleBatchDeleteClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Archive", + icon: , + onClick: handleBatchArchiveClick, + disabled: props.batchActionPending, + }, + { + tooltip: "Run", + icon: , + onClick: handleBatchRunClick, + disabled: props.batchActionPending, + }, + ]} + menuItemActions={[ + { + label: "Delete All", + onClick: handleDeleteAllClick, + disabled: props.allActionPending, + }, + { + label: "Archive All", + onClick: handleArchiveAllClick, + disabled: props.allActionPending, + }, + { + label: "Run All", + onClick: handleRunAllClick, + disabled: props.allActionPending, + }, + ]} + /> + )}
- - - 0 && numSelected < rowCount} - checked={rowCount > 0 && numSelected === rowCount} - onChange={handleSelectAllClick} - inputProps={{ - "aria-label": "select all tasks shown in the table", - }} - /> - - - {columns.map((col) => ( + {!window.READ_ONLY && ( - {col.label} + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={handleSelectAllClick} + inputProps={{ + "aria-label": "select all tasks shown in the table", + }} + /> + - ))} + )} + {columns + .filter((col) => { + // Filter out actions column in readonly mode. + return !window.READ_ONLY || col.key !== "actions"; + }) + .map((col) => ( + + {col.label} + + ))} @@ -384,16 +393,18 @@ function Row(props: RowProps) { selected={props.isSelected} onClick={() => history.push(taskDetailsPath(task.queue, task.id))} > - e.stopPropagation()}> - - ) => - props.onSelectChange(event.target.checked) - } - checked={props.isSelected} - /> - - + {!window.READ_ONLY && ( + e.stopPropagation()}> + + ) => + props.onSelectChange(event.target.checked) + } + checked={props.isSelected} + /> + + + )}
{uuidPrefix(task.id)} @@ -421,52 +432,54 @@ function Row(props: RowProps) { {durationBefore(task.next_process_at)} - e.stopPropagation()} - > - {props.showActions ? ( - - - - - - - - - - - - - - - - - - ) : ( - - - - )} - + {!window.READ_ONLY && ( + e.stopPropagation()} + > + {props.showActions ? ( + + + + + + + + + + + + + + + + + + ) : ( + + + + )} + + )} ); } diff --git a/ui/src/global.d.ts b/ui/src/global.d.ts index 7f137e7..715ab74 100644 --- a/ui/src/global.d.ts +++ b/ui/src/global.d.ts @@ -6,4 +6,7 @@ interface Window { // Prometheus server address to query time series data. // This field is set to empty string by default. Use this field only if it's set. PROMETHEUS_SERVER_ADDRESS: string; + + // If true, app hides buttons/links to make non-GET requests to the API server. + READ_ONLY: boolean; }