Resolve spacetime client binding merge conflicts

This commit is contained in:
2026-04-24 14:44:46 +08:00
parent 4f369617c7
commit f65177b147
26 changed files with 2172 additions and 1020 deletions

View File

@@ -112,3 +112,20 @@ test('creation hub mixes puzzle works into the same grid and uses puzzle tag to
expect(screen.getAllByText('拼图').length).toBeGreaterThan(0);
expect(screen.queryByText('我的拼图作品')).toBeNull();
});
test('creation hub shows delete action for persisted rpg drafts', () => {
render(
<CustomWorldCreationHub
items={[{ ...baseDraftItem, profileId: 'profile-1' }]}
loading={false}
error={null}
onRetry={() => {}}
onCreateType={noopCreateType}
onOpenDraft={() => {}}
onEnterPublished={() => {}}
onDeletePublished={() => {}}
/>,
);
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
});

View File

@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useMemo, useState } from 'react';
import type { CustomWorldWorkSummary } from '../../../packages/shared/src/contracts/customWorldAgent';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
@@ -199,9 +199,7 @@ export function CustomWorldCreationHub({
: null
}
onDelete={
item.kind === 'rpg' &&
item.item.status === 'published' &&
item.item.profileId
item.kind === 'rpg' && item.item.profileId
? () => {
onDeletePublished?.(item.item);
}

View File

@@ -1216,6 +1216,42 @@ export function PlatformEntryFlowShellImpl({
],
);
const handleDeleteLibraryEntry = useCallback(
(entry: CustomWorldLibraryEntry<CustomWorldProfile>) => {
if (!entry.profileId || deletingCreationWorkId) {
return;
}
runProtectedAction(() => {
const confirmed = window.confirm(
`确认删除作品《${entry.worldName}》吗?删除后会从你的作品列表和公开广场中移除。`,
);
if (!confirmed) {
return;
}
setDeletingCreationWorkId(entry.profileId);
platformBootstrap.setPlatformError(null);
void deleteRpgEntryWorldProfile(entry.profileId)
.then(async (entries) => {
platformBootstrap.setSavedCustomWorldEntries(entries);
await platformBootstrap.refreshCustomWorldWorks().catch(() => []);
await platformBootstrap.refreshPublishedGallery().catch(() => []);
})
.catch((error) => {
platformBootstrap.setPlatformError(
resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'),
);
})
.finally(() => {
setDeletingCreationWorkId(null);
});
});
},
[deletingCreationWorkId, platformBootstrap, runProtectedAction],
);
const handleDeletePublishedWork = useCallback(
(work: (typeof creationHubItems)[number]) => {
if (!work.profileId || deletingCreationWorkId) {
@@ -1556,6 +1592,10 @@ export function PlatformEntryFlowShellImpl({
detailNavigation.openLibraryDetail(entry);
});
}}
onDeleteLibraryEntry={(entry) => {
handleDeleteLibraryEntry(entry);
}}
deletingLibraryEntryId={deletingCreationWorkId}
onSearchPublicCode={(keyword) => {
void handlePublicCodeSearch(keyword);
}}

View File

@@ -76,6 +76,10 @@ export interface RpgEntryHomeViewProps {
onOpenLibraryDetail: (
entry: CustomWorldLibraryEntry<CustomWorldProfile>,
) => void;
onDeleteLibraryEntry?: (
entry: CustomWorldLibraryEntry<CustomWorldProfile>,
) => void;
deletingLibraryEntryId?: string | null;
onSearchPublicCode?: (keyword: string) => void | Promise<void>;
isSearchingPublicCode?: boolean;
onOpenProfileDashboardCard?: (cardKey: ProfileDashboardCardKey) => void;
@@ -303,9 +307,13 @@ function WorldCard({
function CreationLibraryCard({
entry,
onClick,
onDelete,
isDeleting = false,
}: {
entry: CustomWorldLibraryEntry<CustomWorldProfile>;
onClick: () => void;
onDelete?: () => void;
isDeleting?: boolean;
}) {
const coverImage = resolvePlatformWorldCoverImage(entry);
const leadPortrait = resolvePlatformWorldLeadPortrait(entry);
@@ -343,6 +351,19 @@ function CreationLibraryCard({
/>
) : null}
<div className="absolute inset-0 bg-[var(--platform-card-overlay-strong)]" />
{onDelete ? (
<button
type="button"
onClick={(event) => {
event.stopPropagation();
onDelete();
}}
disabled={isDeleting}
className="platform-button platform-button--danger absolute right-2 top-2 z-20 min-h-0 rounded-full px-2.5 py-1 text-[10px] disabled:cursor-not-allowed disabled:opacity-60"
>
{isDeleting ? '删除中' : '删除'}
</button>
) : null}
<div className="relative z-10 flex h-full min-w-0 flex-col">
<div className="flex min-w-0 flex-wrap items-center gap-1.5">
<span
@@ -784,6 +805,8 @@ export function RpgEntryHomeView({
onOpenCreateTypePicker,
onOpenGalleryDetail,
onOpenLibraryDetail,
onDeleteLibraryEntry,
deletingLibraryEntryId = null,
onSearchPublicCode,
isSearchingPublicCode = false,
onOpenProfileDashboardCard,
@@ -983,6 +1006,8 @@ export function RpgEntryHomeView({
key={`${entry.ownerUserId}:${entry.profileId}:mine`}
entry={entry}
onClick={() => onOpenLibraryDetail(entry)}
onDelete={onDeleteLibraryEntry ? () => onDeleteLibraryEntry(entry) : undefined}
isDeleting={deletingLibraryEntryId === entry.profileId}
/>
),
)}