feat(npcs): add groups, storyline bindings, and Foundry import
Nested NPC groups with color, graph filter, and scene/storyline binding; Foundry worlds/modules import actors into groups; storyline merge asks on NPC name conflicts and reports NPC counts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { ipcChannels, type ScenePreviewImportEvent } from '../../../shared/ipc/contracts';
|
||||
import type {
|
||||
NpcImportResolution,
|
||||
SceneImportResolution,
|
||||
StorylineImportMergeReport,
|
||||
StorylineLabels,
|
||||
@@ -94,6 +95,10 @@ type Actions = {
|
||||
setSceneListOrder: (sceneListOrder: SceneId[]) => Promise<void>;
|
||||
renameProject: (name: string, fileBaseName: string) => Promise<void>;
|
||||
importProject: () => Promise<void>;
|
||||
pickFoundrySource: (
|
||||
mode: 'folder' | 'archive',
|
||||
) => Promise<{ canceled: true } | { canceled: false; sourcePath: string }>;
|
||||
importFoundryProject: (sourcePath: string) => Promise<void>;
|
||||
peekImportZip: (labels: StorylineLabels, targetHasMainStart: boolean) => Promise<
|
||||
| { canceled: true }
|
||||
| {
|
||||
@@ -129,11 +134,13 @@ type Actions = {
|
||||
filePath: string,
|
||||
storylineSelections: StorylineSelection[],
|
||||
sceneResolutions: SceneImportResolution[],
|
||||
npcResolutions?: NpcImportResolution[],
|
||||
) => Promise<{ project: Project; report: StorylineImportMergeReport }>;
|
||||
mergeImportFromProject: (
|
||||
sourceProjectId: ProjectId,
|
||||
storylineSelections: StorylineSelection[],
|
||||
sceneResolutions: SceneImportResolution[],
|
||||
npcResolutions?: NpcImportResolution[],
|
||||
) => Promise<{ project: Project; report: StorylineImportMergeReport }>;
|
||||
importProjectFromPath: (filePath: string) => Promise<void>;
|
||||
getProjectStorylines: (projectId: ProjectId, labels: StorylineLabels) => Promise<StorylineListItem[]>;
|
||||
@@ -749,6 +756,24 @@ export function useProjectState(licenseActive: boolean, opts?: ProjectStateOpts)
|
||||
}
|
||||
};
|
||||
|
||||
const pickFoundrySource = async (mode: 'folder' | 'archive') => {
|
||||
return api.invoke(ipcChannels.project.pickFoundrySource, { mode });
|
||||
};
|
||||
|
||||
const importFoundryProject = async (sourcePath: string) => {
|
||||
try {
|
||||
const res = await api.invoke(ipcChannels.project.importFoundry, { sourcePath });
|
||||
setState((s) => ({
|
||||
...s,
|
||||
project: res.project,
|
||||
selectedSceneId: res.project.currentSceneId,
|
||||
}));
|
||||
await refreshProjects();
|
||||
} finally {
|
||||
setState((s) => ({ ...s, zipProgress: null }));
|
||||
}
|
||||
};
|
||||
|
||||
const peekImportZip = async (labels: StorylineLabels, targetHasMainStart: boolean) => {
|
||||
return api.invoke(ipcChannels.project.peekImportZip, { labels, targetHasMainStart });
|
||||
};
|
||||
@@ -781,11 +806,13 @@ export function useProjectState(licenseActive: boolean, opts?: ProjectStateOpts)
|
||||
filePath: string,
|
||||
storylineSelections: StorylineSelection[],
|
||||
sceneResolutions: SceneImportResolution[],
|
||||
npcResolutions?: NpcImportResolution[],
|
||||
) => {
|
||||
const res = await api.invoke(ipcChannels.project.mergeImportZip, {
|
||||
filePath,
|
||||
storylineSelections,
|
||||
sceneResolutions,
|
||||
...(npcResolutions ? { npcResolutions } : {}),
|
||||
});
|
||||
setState((s) => ({
|
||||
...s,
|
||||
@@ -799,11 +826,13 @@ export function useProjectState(licenseActive: boolean, opts?: ProjectStateOpts)
|
||||
sourceProjectId: ProjectId,
|
||||
storylineSelections: StorylineSelection[],
|
||||
sceneResolutions: SceneImportResolution[],
|
||||
npcResolutions?: NpcImportResolution[],
|
||||
) => {
|
||||
const res = await api.invoke(ipcChannels.project.mergeImportFromProject, {
|
||||
sourceProjectId,
|
||||
storylineSelections,
|
||||
sceneResolutions,
|
||||
...(npcResolutions ? { npcResolutions } : {}),
|
||||
});
|
||||
setState((s) => ({
|
||||
...s,
|
||||
@@ -884,6 +913,8 @@ export function useProjectState(licenseActive: boolean, opts?: ProjectStateOpts)
|
||||
renameProject,
|
||||
importProject,
|
||||
importProjectFromPath,
|
||||
pickFoundrySource,
|
||||
importFoundryProject,
|
||||
peekImportZip,
|
||||
pickImportZipFile,
|
||||
peekImportZipPath,
|
||||
|
||||
Reference in New Issue
Block a user