{isCondition(snippet)
- ?
+ ?
{__('Back to all conditions', 'code-snippets')}
:
@@ -184,9 +186,12 @@ const EditFormWrap: React.FC = () => {
export const SnippetForm: React.FC = () =>
- {__('You are about to delete this snippet.', 'code-snippets')}{' '}
- {__('Are you sure?', 'code-snippets')}
-
- {__('Prevent accidental changes or deletion.', 'code-snippets')}
- {__('Upload one or more Code Snippets export files and the snippets will be imported.', 'code-snippets')}
- {__('Afterward, you will need to visit the ', 'code-snippets')}
-
- {__('All Snippets', 'code-snippets')}
-
- {__(' page to activate the imported snippets.', 'code-snippets')}
-
- {__('Choose one or more Code Snippets (.xml or .json) files to parse and preview.', 'code-snippets')}
-
- {__('Select the snippets you want to import:', 'code-snippets')}
-
- {__('Drag and drop files here, or click to browse', 'code-snippets')}
-
- {__('Supports JSON and XML files', 'code-snippets')}
-
- {__('What should happen if an existing snippet is found with an identical name to an imported snippet?', 'code-snippets')}
-
- {result.message}
-
- {__('Go to ', 'code-snippets')}
-
- {__('All Snippets', 'code-snippets')}
-
- {__(' to activate your imported snippets.', 'code-snippets')}
- {__('Loading importers...', 'code-snippets')} {__('Error loading importers:', 'code-snippets')} {importerSelection.error} {__('If you are using another Snippets plugin, you can import all existing snippets to your Code Snippets library.', 'code-snippets')}
- {__('No snippets were found for the selected plugin. Make sure the plugin is installed and has snippets configured.', 'code-snippets')}
-
- {__('Loading snippets...', 'code-snippets')}
- {__('We found the following snippets.', 'code-snippets')}
- {message}
- {showSnippetsLink && (
- <>
- {' '}
-
- {__('Code Snippets Library', 'code-snippets')}
- .
- >
- )}
- {__('Loading snippets…', 'code-snippets')} {children} {__('No snippets were found for the selected plugin. Make sure the plugin is installed and has snippets configured.', 'code-snippets')} {__('Loading importers…', 'code-snippets')} {sprintf(__('Error loading importers: %s', 'code-snippets'), error.message)} {__('If you are using another snippets plugin, you can import those existing snippets to your Code Snippets library.', 'code-snippets')} {__('We found the following snippets:', 'code-snippets')} {__('Drag and drop files here, or click to browse', 'code-snippets')} {__('Supports JSON and XML files', 'code-snippets')}
+ {__('What should happen if an existing snippet is found with an identical name to an imported snippet?', 'code-snippets')}
+
+ {__('Choose one or more Code Snippets (.xml or .json) files to parse and preview.', 'code-snippets')}
+ {message}
+ {createInterpolateElement(
+ __('Go to All Snippets to activate your imported snippets.', 'code-snippets'),
+ { a: }
+ )}
+ {__('Select the snippets you would like to import.', 'code-snippets')} {__('Upload one or more Code Snippets export files and the snippets will be imported.', 'code-snippets')}
+ {createInterpolateElement(
+ __('Afterward, you will need to visit the All Snippets page to activate the imported snippets.', 'code-snippets'),
+ { a: }
+ )}
+ {__('An error occurred while fetching search results. Please try again.')} {__('No snippets or codevault could be found with that search term. Please try again.', 'code-snippets')}
+ {snippet.description.length > MAX_DESCRIPTION_LENGTH
+ ? `${snippet.description.slice(0, MAX_DESCRIPTION_LENGTH)}…`
+ : snippet.description}
+
+ {_x('by ', 'snippet author', 'code-snippets')}
+
+ {snippet.codevault}
+
+
+
+ setSearchQuery(event.target.value)}
+ placeholder={__('Search snippets', 'code-snippets')}
+ />
+
+ {__('Warning:', 'code-snippets')}{'\n'}
+ {__('Safe mode is active and snippets will not execute!', 'code-snippets')}{'\n'}
+
+ {createInterpolateElement(
+ __('Remove the {date} {category} {description}
+ {createInterpolateElement(
+ __('This snippet is currently active.', 'code-snippets'),
+ { strong: }
+ )}
+ {__('Moving it to the trash will also deactivate it.', 'code-snippets')}
+ {createInterpolateElement(
+ __('The snippet will be permanently deleted.', 'code-snippets'),
+ { strong: }
+ )}
+ {__('This action cannot be undone.', 'code-snippets')}
+
+ {Object.entries(keyMapLabels).map(([action, label]) => {
+ const keys = shortcutKeys.get(action)
+ return keys
+ ?
+
+
+ : null
+ })}
+
+ {label}
+
+ {isMacOS()
+ ?
+
{snippet.id
? <>
- {`${'condition' === snippet.scope
- ? __('Edit Condition', 'code-snippets')
- : __('Edit Snippet', 'code-snippets')} `}
+ {`${getPageHeading(snippet)} `}
{
- const { snippetsAPI } = useRestAPI()
- const { snippet, setIsWorking, isWorking, handleRequestError } = useSnippetForm()
- const [isDialogOpen, setIsDialogOpen] = useState(false)
-
- return (
- <>
-
-
-
{__('Lock Snippet', 'code-snippets')}
-
-
- {__('Choose Files', 'code-snippets')}
- {__('Available Snippets', 'code-snippets')} ({importWorkflow.availableSnippets.length})
- {__('Duplicate Snippets', 'code-snippets')}
-
- {result.success
- ? __('Import Successful!', 'code-snippets')
- : __('Import Failed', 'code-snippets')
- }
-
-
- {__('Warnings:', 'code-snippets')}
-
-
- {result.warnings.map((warning, index) => (
-
-
- {__('Selected Files:', 'code-snippets')} ({files.length})
-
-
-
-
- )
-}
diff --git a/src/js/components/Import/FromFileUpload/components/index.ts b/src/js/components/Import/FromFileUpload/components/index.ts
deleted file mode 100644
index d05811037..000000000
--- a/src/js/components/Import/FromFileUpload/components/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export { DuplicateActionSelector } from './DuplicateActionSelector'
-export { DragDropUploadArea } from './DragDropUploadArea'
-export { SelectedFilesList } from './SelectedFilesList'
-export { SnippetSelectionTable } from './SnippetSelectionTable'
-export { ImportResultDisplay } from './ImportResultDisplay'
diff --git a/src/js/components/Import/FromFileUpload/hooks/index.ts b/src/js/components/Import/FromFileUpload/hooks/index.ts
deleted file mode 100644
index 5826fc3eb..000000000
--- a/src/js/components/Import/FromFileUpload/hooks/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { useDragAndDrop } from './useDragAndDrop'
-export { useFileSelection } from './useFileSelection'
-export { useSnippetSelection } from './useSnippetSelection'
-export { useImportWorkflow } from './useImportWorkflow'
diff --git a/src/js/components/Import/FromFileUpload/hooks/useDragAndDrop.ts b/src/js/components/Import/FromFileUpload/hooks/useDragAndDrop.ts
deleted file mode 100644
index f6c3b0bb1..000000000
--- a/src/js/components/Import/FromFileUpload/hooks/useDragAndDrop.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { useState } from 'react'
-
-interface UseDragAndDropProps {
- onFilesDrop: (files: FileList) => void
-}
-
-export const useDragAndDrop = ({ onFilesDrop }: UseDragAndDropProps) => {
- const [dragOver, setDragOver] = useState(false)
-
- const handleDragOver = (e: React.DragEvent) => {
- e.preventDefault()
- setDragOver(true)
- }
-
- const handleDragLeave = (e: React.DragEvent) => {
- e.preventDefault()
- setDragOver(false)
- }
-
- const handleDrop = (e: React.DragEvent) => {
- e.preventDefault()
- setDragOver(false)
-
- const files = e.dataTransfer.files
- if (files.length > 0) {
- onFilesDrop(files)
- }
- }
-
- return {
- dragOver,
- handleDragOver,
- handleDragLeave,
- handleDrop
- }
-}
diff --git a/src/js/components/Import/FromFileUpload/hooks/useFileSelection.ts b/src/js/components/Import/FromFileUpload/hooks/useFileSelection.ts
deleted file mode 100644
index 333fa4526..000000000
--- a/src/js/components/Import/FromFileUpload/hooks/useFileSelection.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { useState, useRef } from 'react'
-import { removeFileFromList } from '../utils/fileUtils'
-
-export const useFileSelection = () => {
- const [selectedFiles, setSelectedFiles] = useState
-
-
-
- {snippets.map(snippet => (
-
-
-
- {__('Name', 'code-snippets')}
- {__('Type', 'code-snippets')}
- {__('Description', 'code-snippets')}
- {__('Tags', 'code-snippets')}
-
-
- ))}
-
-
- onSnippetToggle(snippet.table_data.id)}
- />
-
-
- {snippet.table_data.title}
- {snippet.source_file && (
-
-
-
- {snippet.table_data.type}
-
-
-
- {truncateDescription(snippet.table_data.description)}
-
- {snippet.table_data.tags || '—'}
-
- {__('No snippets found', 'code-snippets')}
-
- {__('Import options', 'code-snippets')}
-
- {__('Available Snippets', 'code-snippets')} ({snippets.length})
-
-
-
-
-
-
-
-
- {snippets.map(snippet => (
-
-
-
- {__('Snippet Name', 'code-snippets')}
- {__('ID', 'code-snippets')}
-
-
- ))}
-
-
- onSnippetToggle(snippet.table_data.id)}
- />
-
- {snippet.table_data.title}
- {snippet.table_data.id}
-
- {title}
-
-
- {
- e.preventDefault()
- handleTabChange('upload')
- }}
- >
- {__('Import Snippets', 'code-snippets')}
-
- {
- e.preventDefault()
- handleTabChange('plugins')
- }}
- >
- {__('Import from other plugins', 'code-snippets')}
-
-
-
- {__('Import Snippets', 'code-snippets')}
+
+
+ {TABS.map(tab =>
+ {
+ event.preventDefault()
+ setActiveTab(tab)
+ updateQueryParam('tab', tab)
+ }}
+ >
+ {TAB_LABELS[tab]}
+ )}
+
+
+ {__('Import options', 'code-snippets')}
+
+ {title}
+ {__('No snippets found', 'code-snippets')}
+ {sprintf(
+ // translators: %d: number of available snippets.
+ __('Available snippets (%d)', 'code-snippets'),
+ availableItems.length
+ )}
+
+
+
+
+
+
+
+
+ {availableItems.map(snippet =>
+
+
+
+ {__('Snippet name', 'code-snippets')}
+ {__('ID', 'code-snippets')}
+
+ )}
+
+
+ toggleItem(snippet.table_data.id)}
+ />
+
+ {snippet.table_data.title}
+ {snippet.table_data.id}
+ {__('Duplicate snippets', 'code-snippets')}
+
+ {__('Choose files', 'code-snippets')}
+
+ {sprintf(
+ // translators: %d: number of selected files.
+ __('Selected files: (%d)', 'code-snippets'),
+ files.length
+ )}
+
+
+ {success
+ ? __('Import Successful!', 'code-snippets')
+ : __('Import Failed', 'code-snippets')}
+
+ {__('Warnings:', 'code-snippets')}
+
+ {warnings.map(warning =>
+ {sprintf(
+ // translators: %d: number of available snippets.
+ __('Available snippets (%d)', 'code-snippets'),
+ availableSnippets.length
+ )}
+
+
+
+ >
diff --git a/src/js/components/ImportMenu/UploadForm/UploadForm.tsx b/src/js/components/ImportMenu/UploadForm/UploadForm.tsx
new file mode 100644
index 000000000..9ab9fe551
--- /dev/null
+++ b/src/js/components/ImportMenu/UploadForm/UploadForm.tsx
@@ -0,0 +1,72 @@
+import React, { useRef, useState } from 'react'
+import { __ } from '@wordpress/i18n'
+import { createInterpolateElement } from '@wordpress/element'
+import { ImportResultDisplay } from './SelectSnippets/ImportResultDisplay'
+import { SelectSnippets } from './SelectSnippets/SelectSnippets'
+import { SelectFiles } from './SelectFiles/SelectFiles'
+import { DuplicateActionSelector } from './SelectFiles/DuplicateActionSelector'
+import type { ImportableSnippetSchema } from '../../../types/schema/ImportableSnippetSchema'
+import type { ImportResult} from './SelectSnippets/ImportResultDisplay'
+import type { UploadedFile} from './SelectFiles/SelectFiles'
+import type { DuplicateAction} from './SelectFiles/DuplicateActionSelector'
+
+type Step = 'upload' | 'select'
+
+export const UploadForm: React.FC = () => {
+ const [duplicateAction, setDuplicateAction] = useState
+
+
+
+ {snippets.map(snippet =>
+
+
+
+ {__('Name', 'code-snippets')}
+ {__('Type', 'code-snippets')}
+ {__('Description', 'code-snippets')}
+ {__('Tags', 'code-snippets')}
+
+
+ )}
+
+
+ toggleItem(snippet.table_data.id)}
+ />
+
+
+ {snippet.table_data.title}
+ {snippet.source_file &&
+ {snippet.table_data.type}
+ {truncateDescription(snippet.table_data.description)}
+ {snippet.table_data.tags || '—'}
+ {__('Community Cloud', 'code-snippets')}
+
+
+ {TABS.map(tab =>
+ {
+ event.preventDefault()
+
+ if (PRO_TABS.includes(tab) && !isLicensed()) {
+ setIsUpsellDialogOpen(true)
+ } else {
+ updateQueryParam('tab', tab)
+ setCurrentTab(tab)
+ }
+ }}
+ >
+ {TAB_LABELS[tab]}
+ {PRO_TABS.includes(tab) && !isLicensed() && {__('Pro', 'code-snippets')}}
+ )}
+
+
+ {'snippets' === currentTab
+ ?
+ {
+ event.preventDefault()
+ setIsPreviewOpen(true)
+ }}
+ >
+ {snippet.name}
+
+
+
+
+
+
+ {'php' === snippetType ? '
+
+ {visibleStatuses.map(([status, label], index) =>
+
+ )
+}
+
+const ClearRecentlyActiveButton: React.FC = () => {
+ const { api } = useRestAPI()
+ const { refreshSnippetsList } = useSnippetsList()
+ const { currentStatus } = useSnippetsFilters()
+
+ return 'recently_active' === currentStatus
+ ?
+ {__('Manage Code Snippets', 'code-snippets')}
+
+ {searchQueryText || currentTag
+ ?
+ {__('Search results', 'code-snippets')}
+
+ {/* translators: %s: search query. */}
+ {searchQueryText && sprintf(__(' for “%s”', 'code-snippets'), searchQueryText)}
+
+ {/* translators: %d: code line number. */}
+ {searchLineNumber && sprintf(__(' on line “%d”', 'code-snippets'), searchLineNumber)}
+
+ {/* translators: %s: tag name. */}
+ {currentTag && sprintf(__(' in tag “%s”', 'code-snippets'), currentTag)}
+
+ {' '}
+
+
+ : null}
+
+
+ CODE_SNIPPETS_SAFE_MODE constant from wp-config.php file to turn off safe mode.', 'code-snippets'),
+ {
+ code:
+ }
+ )}{'\n'}
+
+
+ {__('Read more', 'code-snippets')}
+
+
+
+
+
-
- {Object.entries(shortcuts).map(([name, { label, mod, key }]) =>
-
-
- )}
-
- {label}
-
- {(Array.isArray(mod) ? mod : [mod]).map(modifier =>
-
-
-
+
+ {CHANGELOG_LABELS[section]}
+
+
+ {Object.entries(entries).map(([pluginType, changes]) =>
+ changes.map(change =>
+
+ >
+
+export const Changelog = () =>
+ {__('Latest changes', 'code-snippets')}
+
+ {__('View changelog', 'code-snippets')}
+
+ {sprintf(__('Version %s', 'code-snippets'), version)}
+ {DATA?.hero.name}
+
+ {__('Read more', 'code-snippets')}
+
+ setImageLoaded(true)}
+ />
+
{__('Exclusive deals from our partners', 'code-snippets')}
+
+
{title}
+
+ {__('Visit', 'code-snippets')}
+
+ {__('Helpful articles', 'code-snippets')}
+
+
{title}
+ {__('Resources and Updates', 'code-snippets')}
+
+
+
+
+
+ {
+ event.preventDefault()
+ setSortColumn(column)
+ setSortDirection(newSortDirection)
+ }}>
+ {column.title}
+
+
+
+
+ {isCurrent ? null
+ :
+ {/* translators: Hidden accessibility text. */}
+ {'asc' === newSortDirection ? __('Sort ascending.', 'code-snippets') : __('Sort descending.', 'code-snippets')}
+ }
+
+
+ )
+}
+
+export interface TableHeadingsProps
+
diff --git a/src/js/components/common/ListTable/TableItems.tsx b/src/js/components/common/ListTable/TableItems.tsx
new file mode 100644
index 000000000..7fd3ea00e
--- /dev/null
+++ b/src/js/components/common/ListTable/TableItems.tsx
@@ -0,0 +1,61 @@
+import React from 'react'
+import type { Dispatch, Key, SetStateAction } from 'react'
+import type { ListTableColumn, ListTableItemsProps } from './ListTable'
+
+interface CheckboxCellProps
+ {
+ setSelected(new Set(event.target.checked ? items.map(getKey) : null))
+ }}
+ />
+
+
+ {columns.map(column => {
+ const cellProps: ThHTMLAttributes{column.title}
+ })}
+
+ {
+ setSelected(previous => {
+ const updated = new Set(previous)
+
+ if (event.target.checked) {
+ updated.add(getKey(item))
+ } else {
+ updated.delete(getKey(item))
+ }
+
+ return updated
+ })
+ }}
+ />
+
+
+interface TableCellProps{column.render(item)}
+ : {column.render(item)}
+}
+
+export interface TableItemsProps
+
+ )
+ :
+
diff --git a/src/js/components/common/ListTable/TableNav.tsx b/src/js/components/common/ListTable/TableNav.tsx
new file mode 100644
index 000000000..acb8be108
--- /dev/null
+++ b/src/js/components/common/ListTable/TableNav.tsx
@@ -0,0 +1,119 @@
+import React, { useMemo, useState } from 'react'
+import { __ } from '@wordpress/i18n'
+import { Spinner } from '@wordpress/components'
+import { handleUnknownError } from '../../../utils/errors'
+import { SubmitButton } from '../SubmitButton'
+import { TablePagination } from './TablePagination'
+import type { TablePaginationProps } from './TablePagination'
+import type { ListTableBulkAction, ListTableNavProps } from './ListTable'
+import type { Key } from 'react'
+
+interface BulkActionSelectProps{noItems}
+