Added basic support for linking DatasetBuilder datasets to lcp-data-collection CPT, and support for deleting datasets and datapoint in the DatasetBuilder.

This commit is contained in:
Jeremy Rangel
2025-01-16 18:39:08 -08:00
parent 436af3dd29
commit 197c9fd3da
4 changed files with 199 additions and 43 deletions

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'a7190cef9649b69f1e40');
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'e934cc621b90f4fd2b9c');

File diff suppressed because one or more lines are too long

View File

@ -14,12 +14,13 @@ import {
import { useState, useRef } from '@wordpress/element';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import apiFetch from '@wordpress/api-fetch';
const ItemTypes = {
DATASET_ITEM: 'dataset_item'
};
const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items }) => {
const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items, onDelete }) => {
const [showColorPicker, setShowColorPicker] = useState(false);
const ref = useRef(null);
@ -132,6 +133,18 @@ const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items }) => {
</Popover>
)}
</div>
<Button
variant="secondary"
isDestructive
isSmall
onClick={() => {
if (window.confirm(__('Are you sure you want to delete this item?', 'lcp'))) {
onDelete(item.id);
}
}}
>
{__('Delete', 'lcp')}
</Button>
</div>
</CardBody>
</Card>
@ -145,6 +158,7 @@ const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items }) => {
moveItem={moveItem}
updateItem={updateItem}
items={items}
onDelete={onDelete}
/>
))}
</div>
@ -154,14 +168,25 @@ const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items }) => {
const LCPDatasetBuilder = ({ value, onChange }) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasets, setDatasets] = useState(value || {});
const [isSaving, setIsSaving] = useState(false);
const [editingDataset, setEditingDataset] = useState(null);
const addNewDataset = () => {
const newDatasetName = `Dataset ${Object.keys(datasets).length + 1}`;
const defaultName = 'New Dataset';
let newName = defaultName;
let counter = 1;
// Ensure unique name
while (datasets[newName]) {
newName = `${defaultName} ${counter}`;
counter++;
}
const updatedDatasets = {
...datasets,
[newDatasetName]: [{
[newName]: [{
id: `dataset-${Date.now()}`,
label: newDatasetName,
label: 'New Item',
parent: null,
value: 0,
color: '#000000'
@ -169,6 +194,44 @@ const LCPDatasetBuilder = ({ value, onChange }) => {
};
setDatasets(updatedDatasets);
onChange(updatedDatasets);
setEditingDataset(newName);
};
const renameDataset = (oldName, newName) => {
if (oldName === newName || !newName.trim() || datasets[newName]) {
setEditingDataset(null);
return;
}
const updatedDatasets = { ...datasets };
updatedDatasets[newName] = updatedDatasets[oldName];
delete updatedDatasets[oldName];
setDatasets(updatedDatasets);
onChange(updatedDatasets);
setEditingDataset(null);
};
const deleteDataset = (datasetKey) => {
const updatedDatasets = { ...datasets };
delete updatedDatasets[datasetKey];
setDatasets(updatedDatasets);
onChange(updatedDatasets);
};
const deleteItem = (datasetKey, itemId) => {
const updatedDatasets = { ...datasets };
// Remove the item and its children
const removeItemAndChildren = (items, targetId) => {
return items.filter(item => {
if (item.id === targetId) return false;
if (item.parent === targetId) return false;
return true;
});
};
updatedDatasets[datasetKey] = removeItemAndChildren(updatedDatasets[datasetKey], itemId);
setDatasets(updatedDatasets);
onChange(updatedDatasets);
};
const addNewItem = (datasetKey) => {
@ -231,45 +294,127 @@ const LCPDatasetBuilder = ({ value, onChange }) => {
onChange(updatedDatasets);
};
const saveToCollection = async () => {
try {
setIsSaving(true);
console.log('Chart data:', datasets);
const formattedDatasets = Object.entries(datasets).map(([name, data]) => ({
dataset_name: name,
dataset_source: 'json',
dataset_json: data
}));
console.log('Formatted datasets:', formattedDatasets);
// Create the post first
const postResponse = await apiFetch({
path: '/wp/v2/lcp-data-collection',
method: 'POST',
data: {
title: Object.keys(datasets)[0] || 'Dataset Collection',
status: 'publish',
meta: {
lcp_datasets: formattedDatasets
}
}
});
console.log('Post created:', postResponse);
console.log('Meta data in response:', postResponse.meta);
// Double-check the meta was saved by fetching the post
const savedPost = await apiFetch({
path: `/wp/v2/lcp-data-collection/${postResponse.id}`,
method: 'GET'
});
console.log('Saved post data:', savedPost);
console.log('Saved meta data:', savedPost.meta?.lcp_datasets);
} catch (error) {
console.error('Error saving dataset:', error);
console.log('Error details:', {
message: error.message,
code: error.code,
data: error.data
});
} finally {
setIsSaving(false);
}
};
return (
<>
<Button
variant="primary"
onClick={() => {
setIsModalOpen(true);
if (Object.keys(datasets).length === 0) {
addNewDataset();
}
}}
onClick={() => setIsModalOpen(true)}
>
{__('Open Dataset Builder', 'lcp')}
</Button>
{isModalOpen && (
<Modal
title={__('Dataset Builder', 'lcp')}
onRequestClose={() => setIsModalOpen(false)}
style={{ width: '90vw' }}
style={{ width: '100%', maxWidth: '800px' }}
>
<DndProvider backend={HTML5Backend}>
<div style={{ padding: '20px' }}>
{Object.entries(datasets).map(([datasetKey, items]) => (
<div key={datasetKey} style={{ marginBottom: '20px' }}>
<h3>{datasetKey}</h3>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px' }}>
{editingDataset === datasetKey ? (
<TextControl
value={datasetKey}
onChange={(newName) => renameDataset(datasetKey, newName)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
renameDataset(datasetKey, e.target.value);
} else if (e.key === 'Escape') {
setEditingDataset(null);
}
}}
autoFocus
/>
) : (
<>
<h3 style={{ margin: 0 }}>{datasetKey}</h3>
<Button
variant="secondary"
isSmall
onClick={() => setEditingDataset(datasetKey)}
>
{__('Rename', 'lcp')}
</Button>
<Button
variant="secondary"
isDestructive
isSmall
onClick={() => {
if (window.confirm(__('Are you sure you want to delete this dataset?', 'lcp'))) {
deleteDataset(datasetKey);
}
}}
>
{__('Delete', 'lcp')}
</Button>
</>
)}
</div>
<div>
{items
.filter(item => !item.parent) // Only render top-level items
.filter(item => !item.parent)
.map(item => (
<DatasetItem
key={item.id}
item={item}
datasetKey={datasetKey}
item={item}
items={items}
moveItem={moveItem}
updateItem={updateItem}
items={items}
onDelete={(itemId) => deleteItem(datasetKey, itemId)}
/>
))
}
))}
</div>
<Button
variant="secondary"
@ -280,13 +425,21 @@ const LCPDatasetBuilder = ({ value, onChange }) => {
</Button>
</div>
))}
<Button
variant="primary"
onClick={addNewDataset}
style={{ marginTop: '20px' }}
>
{__('Add New Dataset', 'lcp')}
</Button>
<div style={{ display: 'flex', gap: '10px', marginTop: '20px' }}>
<Button
variant="primary"
onClick={addNewDataset}
>
{__('Add New Dataset', 'lcp')}
</Button>
<Button
variant="secondary"
onClick={saveToCollection}
disabled={isSaving}
>
{isSaving ? __('Saving...', 'lcp') : __('Save to Collection', 'lcp')}
</Button>
</div>
</div>
</DndProvider>
</Modal>

View File

@ -99,26 +99,29 @@ add_action('init', 'lcp_register_data_collection_post_type');
// Register meta field for datasets
function lcp_register_meta_fields() {
register_post_meta('lcp-data-collection', 'lcp_datasets', array(
'show_in_rest' => true,
'show_in_rest' => array(
'schema' => array(
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'dataset_name' => array(
'type' => 'string'
),
'dataset_source' => array(
'type' => 'string'
),
'dataset_json' => array(
'type' => 'array'
)
)
)
)
),
'single' => true,
'type' => 'array',
'auth_callback' => function() {
return current_user_can('edit_posts');
},
'sanitize_callback' => function($meta_value) {
if (!is_array($meta_value)) {
return array();
}
$sanitized = array();
foreach ($meta_value as $key => $dataset) {
$sanitized[$key] = array(
'dataset_name' => sanitize_text_field($dataset['dataset_name']),
'dataset_source' => sanitize_text_field($dataset['dataset_source']),
'dataset_json' => json_decode(wp_unslash($dataset['dataset_json']), true)
);
}
return $sanitized;
}
));
}