PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / ManageMenu / SnippetsTable / RowActions.tsx

RowActions.tsx in Code Snippets 3.10.2, at js/components/ManageMenu/SnippetsTable/RowActions.tsx

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