← All changes
|
js/components/ManageMenu/SnippetsTable/RowActions.tsx
+54
-58
3.10.0-beta.1
→
trunk
View file →
| @@ -5,12 +5,12 @@ | ||
| 5 | 5 | import { useSnippetsAPI } from '../../../hooks/useSnippetsAPI' |
| 6 | 6 | import { useSnippetsList } from '../../../hooks/useSnippetsList' |
| 7 | 7 | import { downloadSnippetExportFile } from '../../../utils/files' |
| 8 | 8 | import { isNetworkAdmin } from '../../../utils/screen' |
| 9 | -import { cloneSnippetObject, getSnippetDisplayName, getSnippetEditUrl, getSnippetType } from '../../../utils/snippets/snippets' | |
| 9 | +import { cloneSnippetObject, getSnippetEditUrl } from '../../../utils/snippets/snippets' | |
| 10 | 10 | import { Button } from '../../common/Button' |
| 11 | -import { DeleteButton } from '../../common/DeleteButton' | |
| 12 | -import { SnippetPreviewModal } from '../../common/SnippetPreviewModal' | |
| 11 | +import { SnippetPreviewModal } from '../../common/snippets/SnippetPreviewModal' | |
| 12 | +import { ConfirmDeleteDialog, useDeleteSnippet } from '../../common/snippets/ConfirmDeleteDialog' | |
| 13 | 13 | import type { ReactNode } from 'react' |
| 14 | 14 | import type { Snippet } from '../../../types/Snippet' |
| 15 | 15 | |
| 16 | 16 | interface RowActionsProps { |
| @@ -16,9 +16,9 @@ | ||
| 16 | 16 | interface RowActionsProps { |
| 17 | 17 | snippet: Snippet |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | -const PreviewLink: React.FC<RowActionsProps> = ({ snippet }) => { | |
| 20 | +const PreviewButton: React.FC<RowActionsProps> = ({ snippet }) => { | |
| 21 | 21 | const [isPreviewOpen, setIsPreviewOpen] = useState(false) |
| 22 | 22 | |
| 23 | 23 | return ( |
| 24 | 24 | <> |
| @@ -25,16 +25,13 @@ | ||
| 25 | 25 | <Button link onClick={() => setIsPreviewOpen(true)}> |
| 26 | 26 | {__('Preview', 'code-snippets')} |
| 27 | 27 | </Button> |
| 28 | 28 | |
| 29 | - <SnippetPreviewModal | |
| 30 | - title={getSnippetDisplayName(snippet)} | |
| 31 | - code={snippet.code} | |
| 32 | - type={getSnippetType(snippet)} | |
| 33 | - isOpen={isPreviewOpen} | |
| 34 | - setIsOpen={setIsPreviewOpen} | |
| 35 | - snippet={snippet} | |
| 36 | - /> | |
| 29 | + {isPreviewOpen && ( | |
| 30 | + <SnippetPreviewModal | |
| 31 | + snippet={snippet} | |
| 32 | + setIsOpen={setIsPreviewOpen} | |
| 33 | + />)} | |
| 37 | 34 | </> |
| 38 | 35 | ) |
| 39 | 36 | } |
| 40 | 37 | |
| @@ -50,30 +47,8 @@ | ||
| 50 | 47 | |
| 51 | 48 | const SnippetActionButton: React.FC<SnippetActionButtonProps> = ({ action, label, workingLabel, failedLabel, className }) => { |
| 52 | 49 | const [status, setStatus] = useState(SnippetActionStatus.Ready) |
| 53 | 50 | |
| 54 | - const ButtonContent = () => { | |
| 55 | - switch (status) { | |
| 56 | - case SnippetActionStatus.Working: | |
| 57 | - return ( | |
| 58 | - <span className="snippet-row-action-feedback"> | |
| 59 | - <Spinner /> {workingLabel ?? __('Loading…', 'code-snippets')} | |
| 60 | - </span> | |
| 61 | - ) | |
| 62 | - | |
| 63 | - case SnippetActionStatus.Errored: | |
| 64 | - return ( | |
| 65 | - <span className="snippet-row-action-error"> | |
| 66 | - <span className="dashicons dashicons-warning"></span> | |
| 67 | - {failedLabel ?? __('Failed', 'code-snippets')} | |
| 68 | - </span> | |
| 69 | - ) | |
| 70 | - | |
| 71 | - default: | |
| 72 | - return label | |
| 73 | - } | |
| 74 | - } | |
| 75 | - | |
| 76 | 51 | return ( |
| 77 | 52 | <Button |
| 78 | 53 | link |
| 79 | 54 | className={classnames(className, { 'is-busy': status === SnippetActionStatus.Working })} |
| @@ -100,43 +75,64 @@ | ||
| 100 | 75 | } |
| 101 | 76 | } |
| 102 | 77 | }} |
| 103 | 78 | > |
| 104 | - <ButtonContent /> | |
| 79 | + {(() => { | |
| 80 | + switch (status) { | |
| 81 | + case SnippetActionStatus.Working: | |
| 82 | + return ( | |
| 83 | + <span className="snippet-row-action-feedback"> | |
| 84 | + <Spinner /> {workingLabel ?? __('Loading…', 'code-snippets')} | |
| 85 | + </span> | |
| 86 | + ) | |
| 87 | + | |
| 88 | + case SnippetActionStatus.Errored: | |
| 89 | + return ( | |
| 90 | + <span className="snippet-row-action-error"> | |
| 91 | + <span className="dashicons dashicons-warning"></span> | |
| 92 | + {failedLabel ?? __('Failed', 'code-snippets')} | |
| 93 | + </span> | |
| 94 | + ) | |
| 95 | + | |
| 96 | + default: | |
| 97 | + return label | |
| 98 | + } | |
| 99 | + })()} | |
| 105 | 100 | </Button> |
| 106 | 101 | ) |
| 107 | 102 | } |
| 103 | +const DeleteActionLink: React.FC<RowActionsProps> = ({ snippet }) => { | |
| 104 | + const { refreshSnippetsList } = useSnippetsList() | |
| 105 | + const { requestDelete, deleteDialogProps } = useDeleteSnippet({ snippet, onSuccess: refreshSnippetsList }) | |
| 108 | 106 | |
| 109 | -const DeleteActionLink: React.FC<{ snippet: Snippet; onSuccess: () => Promise<void> }> = ({ snippet, onSuccess }) => { | |
| 110 | - const [isDeleting, setIsDeleting] = useState(false) | |
| 111 | - | |
| 112 | 107 | return ( |
| 113 | 108 | <> |
| 114 | - <DeleteButton | |
| 115 | - link | |
| 116 | - className={classnames('delete')} | |
| 117 | - snippet={snippet} | |
| 118 | - setIsWorking={setIsDeleting} | |
| 119 | - onSuccess={onSuccess} | |
| 109 | + <SnippetActionButton | |
| 110 | + action={requestDelete} | |
| 111 | + className="delete" | |
| 112 | + label={snippet.trashed ? __('Delete Permanently', 'code-snippets') : __('Trash', 'code-snippets')} | |
| 113 | + workingLabel={snippet.trashed ? __('Deleting…', 'code-snippets') : __('Trashing…', 'code-snippets')} | |
| 114 | + failedLabel={__('Failed to delete', 'code-snippets')} | |
| 120 | 115 | /> |
| 121 | - {isDeleting ? <span className="snippet-row-action-feedback"><Spinner /> {__('Deleting…', 'code-snippets')}</span> : null} | |
| 116 | + | |
| 117 | + <ConfirmDeleteDialog {...deleteDialogProps} /> | |
| 122 | 118 | </> |
| 123 | 119 | ) |
| 124 | 120 | } |
| 125 | 121 | |
| 126 | -const ActionLinks = ({ snippet }: { snippet: Snippet }) => { | |
| 122 | +const ActionLinks: React.FC<RowActionsProps> = ({ snippet }) => { | |
| 127 | 123 | const api = useSnippetsAPI() |
| 128 | 124 | const { refreshSnippetsList } = useSnippetsList() |
| 129 | 125 | |
| 130 | - const Preview = !snippet.trashed ? <PreviewLink snippet={snippet} /> : null | |
| 126 | + const previewButton = !snippet.trashed ? <PreviewButton snippet={snippet} /> : null | |
| 131 | 127 | |
| 132 | - const Edit = !snippet.trashed | |
| 128 | + const editLink = !snippet.trashed | |
| 133 | 129 | ? <a href={getSnippetEditUrl(snippet)}> |
| 134 | 130 | {snippet.locked ? __('View', 'code-snippets') : __('Edit', 'code-snippets')} |
| 135 | 131 | </a> |
| 136 | 132 | : null |
| 137 | 133 | |
| 138 | - const Clone = !snippet.trashed | |
| 134 | + const cloneButton = !snippet.trashed | |
| 139 | 135 | ? <SnippetActionButton |
| 140 | 136 | label={__('Clone', 'code-snippets')} |
| 141 | 137 | workingLabel={__('Cloning…', 'code-snippets')} |
| 142 | 138 | action={() => api.create(cloneSnippetObject(snippet)).then(refreshSnippetsList)} |
| @@ -142,9 +138,9 @@ | ||
| 142 | 138 | action={() => api.create(cloneSnippetObject(snippet)).then(refreshSnippetsList)} |
| 143 | 139 | /> |
| 144 | 140 | : null |
| 145 | 141 | |
| 146 | - const Export = !snippet.trashed | |
| 142 | + const exportButton = !snippet.trashed | |
| 147 | 143 | ? <SnippetActionButton |
| 148 | 144 | label={__('Export', 'code-snippets')} |
| 149 | 145 | workingLabel={__('Exporting…', 'code-snippets')} |
| 150 | 146 | action={() => |
| @@ -152,9 +148,9 @@ | ||
| 152 | 148 | .then(response => downloadSnippetExportFile(response, snippet))} |
| 153 | 149 | /> |
| 154 | 150 | : null |
| 155 | 151 | |
| 156 | - const Restore = snippet.trashed | |
| 152 | + const restoreButton = snippet.trashed | |
| 157 | 153 | ? <SnippetActionButton |
| 158 | 154 | label={__('Restore', 'code-snippets')} |
| 159 | 155 | workingLabel={__('Restoring…', 'code-snippets')} |
| 160 | 156 | action={() => api.restore(snippet).then(refreshSnippetsList)} |
| @@ -160,19 +156,19 @@ | ||
| 160 | 156 | action={() => api.restore(snippet).then(refreshSnippetsList)} |
| 161 | 157 | /> |
| 162 | 158 | : null |
| 163 | 159 | |
| 164 | - const Delete = !snippet.locked || snippet.trashed | |
| 165 | - ? <DeleteActionLink snippet={snippet} onSuccess={refreshSnippetsList} /> | |
| 160 | + const deleteButton = !snippet.locked || snippet.trashed | |
| 161 | + ? <DeleteActionLink snippet={snippet} /> | |
| 166 | 162 | : null |
| 167 | 163 | |
| 168 | 164 | return ( |
| 169 | 165 | <> |
| 170 | - {[Preview, Edit, Clone, Restore, Export, Delete] | |
| 171 | - .filter(Action => Action) | |
| 166 | + {[previewButton, editLink, cloneButton, restoreButton, exportButton, deleteButton] | |
| 167 | + .filter(action => action) | |
| 172 | 168 | .reduce<ReactNode>( |
| 173 | - (Actions, Action) => | |
| 174 | - null === Actions ? <>{Action}</> : <>{Actions} | {Action}</>, | |
| 169 | + (actions, action) => | |
| 170 | + null === actions ? <>{action}</> : <>{actions} | {action}</>, | |
| 175 | 171 | null)} |
| 176 | 172 | </> |
| 177 | 173 | ) |
| 178 | 174 | } |
| @@ -188,9 +184,9 @@ | ||
| 188 | 184 | ) |
| 189 | 185 | } |
| 190 | 186 | |
| 191 | 187 | if (snippet.shared_network && !window.CODE_SNIPPETS_MANAGE?.hasNetworkCap) { |
| 192 | - return undefined | |
| 188 | + return null | |
| 193 | 189 | } |
| 194 | 190 | |
| 195 | 191 | return ( |
| 196 | 192 | <div className={classnames('row-actions', { visible: !snippet.trashed })}> |