PluginProbe
Code Snippets / 3.10.0-beta.1
Code Snippets v3.10.0-beta.1
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.0-beta.1, at js/components/ManageMenu/SnippetsTable/RowActions.tsx

201 lines 5.4 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, getSnippetDisplayName, getSnippetEditUrl, getSnippetType } from '../../../utils/snippets/snippets'
10 import { Button } from '../../common/Button'
11 import { DeleteButton } from '../../common/DeleteButton'
12 import { SnippetPreviewModal } from '../../common/SnippetPreviewModal'
13 import type { ReactNode } from 'react'
14 import type { Snippet } from '../../../types/Snippet'
15
16 interface RowActionsProps {
17 snippet: Snippet
18 }
19
20 const PreviewLink: 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 <SnippetPreviewModal
30 title={getSnippetDisplayName(snippet)}
31 code={snippet.code}
32 type={getSnippetType(snippet)}
33 isOpen={isPreviewOpen}
34 setIsOpen={setIsPreviewOpen}
35 snippet={snippet}
36 />
37 </>
38 )
39 }
40
41 interface SnippetActionButtonProps {
42 action: () => Promise<unknown>
43 label: ReactNode
44 workingLabel?: string
45 failedLabel?: string
46 className?: string
47 }
48
49 enum SnippetActionStatus { Ready, Working, Errored }
50
51 const SnippetActionButton: React.FC<SnippetActionButtonProps> = ({ action, label, workingLabel, failedLabel, className }) => {
52 const [status, setStatus] = useState(SnippetActionStatus.Ready)
53
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 return (
77 <Button
78 link
79 className={classnames(className, { 'is-busy': status === SnippetActionStatus.Working })}
80 disabled={status === SnippetActionStatus.Working}
81 onClick={() => {
82 switch (status) {
83 case SnippetActionStatus.Errored:
84 setStatus(SnippetActionStatus.Ready)
85 break
86
87 case SnippetActionStatus.Working:
88 break
89
90 case SnippetActionStatus.Ready: {
91 setStatus(SnippetActionStatus.Working)
92
93 action()
94 .then(() => setStatus(SnippetActionStatus.Ready))
95 .catch(() => {
96 setStatus(SnippetActionStatus.Errored)
97 })
98
99 break
100 }
101 }
102 }}
103 >
104 <ButtonContent />
105 </Button>
106 )
107 }
108
109 const DeleteActionLink: React.FC<{ snippet: Snippet; onSuccess: () => Promise<void> }> = ({ snippet, onSuccess }) => {
110 const [isDeleting, setIsDeleting] = useState(false)
111
112 return (
113 <>
114 <DeleteButton
115 link
116 className={classnames('delete')}
117 snippet={snippet}
118 setIsWorking={setIsDeleting}
119 onSuccess={onSuccess}
120 />
121 {isDeleting ? <span className="snippet-row-action-feedback"><Spinner /> {__('Deleting…', 'code-snippets')}</span> : null}
122 </>
123 )
124 }
125
126 const ActionLinks = ({ snippet }: { snippet: Snippet }) => {
127 const api = useSnippetsAPI()
128 const { refreshSnippetsList } = useSnippetsList()
129
130 const Preview = !snippet.trashed ? <PreviewLink snippet={snippet} /> : null
131
132 const Edit = !snippet.trashed
133 ? <a href={getSnippetEditUrl(snippet)}>
134 {snippet.locked ? __('View', 'code-snippets') : __('Edit', 'code-snippets')}
135 </a>
136 : null
137
138 const Clone = !snippet.trashed
139 ? <SnippetActionButton
140 label={__('Clone', 'code-snippets')}
141 workingLabel={__('Cloning…', 'code-snippets')}
142 action={() => api.create(cloneSnippetObject(snippet)).then(refreshSnippetsList)}
143 />
144 : null
145
146 const Export = !snippet.trashed
147 ? <SnippetActionButton
148 label={__('Export', 'code-snippets')}
149 workingLabel={__('Exporting…', 'code-snippets')}
150 action={() =>
151 api.export(snippet)
152 .then(response => downloadSnippetExportFile(response, snippet))}
153 />
154 : null
155
156 const Restore = snippet.trashed
157 ? <SnippetActionButton
158 label={__('Restore', 'code-snippets')}
159 workingLabel={__('Restoring…', 'code-snippets')}
160 action={() => api.restore(snippet).then(refreshSnippetsList)}
161 />
162 : null
163
164 const Delete = !snippet.locked || snippet.trashed
165 ? <DeleteActionLink snippet={snippet} onSuccess={refreshSnippetsList} />
166 : null
167
168 return (
169 <>
170 {[Preview, Edit, Clone, Restore, Export, Delete]
171 .filter(Action => Action)
172 .reduce<ReactNode>(
173 (Actions, Action) =>
174 null === Actions ? <>{Action}</> : <>{Actions} | {Action}</>,
175 null)}
176 </>
177 )
178 }
179
180 export const RowActions: React.FC<RowActionsProps> = ({ snippet }) => {
181 if (!isNetworkAdmin() && snippet.network && !snippet.shared_network) {
182 return (
183 <div className="row-actions visible">
184 {snippet.active
185 ? <span className="network-active">{__('Network Active', 'code-snippets')}</span>
186 : <span className="network-only">{__('Network Only', 'code-snippets')}</span>}
187 </div>
188 )
189 }
190
191 if (snippet.shared_network && !window.CODE_SNIPPETS_MANAGE?.hasNetworkCap) {
192 return undefined
193 }
194
195 return (
196 <div className={classnames('row-actions', { visible: !snippet.trashed })}>
197 <ActionLinks snippet={snippet} />
198 </div>
199 )
200 }
201