mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
feat(furni-editor): sync empty public_name from furnidata name
When a furni has a matching furnidata entry with a display name but its
items_base.public_name (the DB fallback) is empty, the editor now shows a
'Sync from furnidata' button next to the Public Name field. It reuses the
generic item update (a partial { publicName } payload) to fill the DB column
from the stored furnidata name, so the read-only fallback stops being blank.
Button shows only when the entry's classname matches, the DB field is empty,
and the furnidata name is present; it disappears after the sync re-fetch.
This commit is contained in:
@@ -19,7 +19,7 @@ export const FurniEditorView: FC<{}> = () =>
|
||||
selectedItem, setSelectedItem, furniDataEntry, furniDataDiagnostic,
|
||||
interactions,
|
||||
searchItems, loadDetail, loadBySpriteId, updateItem, deleteItem, loadInteractions,
|
||||
updateFurnidata, revertFurnidata, importText, importResult
|
||||
updateFurnidata, revertFurnidata, syncPublicName, importText, importResult
|
||||
} = useFurniEditor();
|
||||
|
||||
const isMod = useHasPermission('acc_catalogfurni');
|
||||
@@ -159,6 +159,7 @@ export const FurniEditorView: FC<{}> = () =>
|
||||
onBack={ handleBack }
|
||||
onUpdateFurnidata={ updateFurnidata }
|
||||
onRevertFurnidata={ revertFurnidata }
|
||||
onSyncPublicName={ syncPublicName }
|
||||
onImportText={ importText }
|
||||
importResult={ importResult }
|
||||
/>
|
||||
|
||||
@@ -15,6 +15,7 @@ interface FurniEditorEditViewProps
|
||||
onBack: () => void;
|
||||
onUpdateFurnidata: (id: number, name: string, description: string) => void;
|
||||
onRevertFurnidata: (id: number) => void;
|
||||
onSyncPublicName: (id: number, name: string) => void;
|
||||
onImportText: (id: number) => void;
|
||||
importResult: { found: boolean; name: string; description: string; classname: string; nonce: number } | null;
|
||||
}
|
||||
@@ -122,7 +123,7 @@ const CopyValue: FC<{ value: string | number }> = ({ value }) =>
|
||||
|
||||
export const FurniEditorEditView: FC<FurniEditorEditViewProps> = props =>
|
||||
{
|
||||
const { item, furniDataEntry, furniDataDiagnostic, interactions, loading, onUpdate, onDelete, onBack, onUpdateFurnidata, onRevertFurnidata, onImportText, importResult } = props;
|
||||
const { item, furniDataEntry, furniDataDiagnostic, interactions, loading, onUpdate, onDelete, onBack, onUpdateFurnidata, onRevertFurnidata, onSyncPublicName, onImportText, importResult } = props;
|
||||
const saveRef = useRef<() => void>(null);
|
||||
|
||||
const [ form, setForm ] = useState({
|
||||
@@ -251,6 +252,15 @@ export const FurniEditorEditView: FC<FurniEditorEditViewProps> = props =>
|
||||
// classname), which stays locked to avoid an id collision.
|
||||
const furnidataCreatable = useMemo(() => !furniDataEntry, [ furniDataEntry ]);
|
||||
|
||||
// Show a one-click "sync" when the DB public_name is empty but the (matching)
|
||||
// furnidata entry already has a name — fills items_base.public_name from the
|
||||
// stored furnidata name so the DB fallback stops being blank.
|
||||
const canSyncPublicName = useMemo(() =>
|
||||
furnidataEditable &&
|
||||
!String(form.publicName ?? '').trim() &&
|
||||
!!String(furniDataEntry?.name ?? '').trim(),
|
||||
[ furnidataEditable, form.publicName, furniDataEntry ]);
|
||||
|
||||
// True only when the name/description actually differ from the stored furnidata
|
||||
// entry. Used to gate the Save button: saving an unchanged value makes the
|
||||
// server writer return false, which the handler misreports as "Classname not
|
||||
@@ -427,6 +437,10 @@ export const FurniEditorEditView: FC<FurniEditorEditViewProps> = props =>
|
||||
<div>
|
||||
<label className={ labelClass }>Public Name (DB fallback)</label>
|
||||
<CopyValue value={ form.publicName } />
|
||||
{ canSyncPublicName &&
|
||||
<Button variant="secondary" disabled={ loading } className="mt-1 w-full" onClick={ () => onSyncPublicName(item.id, String(furniDataEntry?.name ?? '')) }>
|
||||
Sync from furnidata
|
||||
</Button> }
|
||||
</div>
|
||||
<div>
|
||||
<label className={ labelClass }>Sprite ID</label>
|
||||
|
||||
@@ -291,6 +291,17 @@ export const useFurniEditor = () =>
|
||||
SendMessageComposer(new FurniEditorRevertFurnidataComposer(id));
|
||||
}, []);
|
||||
|
||||
// Fill an empty items_base.public_name from the furnidata display name. Reuses
|
||||
// the generic item update (a partial { publicName } payload is accepted), so the
|
||||
// existing 'update' result path shows the toast and re-fetches the detail.
|
||||
const syncPublicName = useCallback((id: number, name: string) =>
|
||||
{
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
pendingActionRef.current = { action: 'update', itemId: id };
|
||||
SendMessageComposer(new FurniEditorUpdateComposer(id, JSON.stringify({ publicName: name })));
|
||||
}, []);
|
||||
|
||||
const importText = useCallback((id: number) =>
|
||||
{
|
||||
setLoading(true);
|
||||
@@ -323,6 +334,6 @@ export const useFurniEditor = () =>
|
||||
selectedItem, setSelectedItem, catalogItems, furniDataEntry, furniDataDiagnostic,
|
||||
interactions,
|
||||
searchItems, loadDetail, loadBySpriteId, updateItem, deleteItem, loadInteractions,
|
||||
updateFurnidata, revertFurnidata, importText, importResult
|
||||
updateFurnidata, revertFurnidata, syncPublicName, importText, importResult
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user