feat: add durable workspace identities
This commit is contained in:
@@ -1950,6 +1950,29 @@ func (a *App) ListWorkspaceTemplates() ([]workspace.WorkspaceTemplate, string) {
|
||||
return a.workspace.ListWorkspaceTemplates(), ""
|
||||
}
|
||||
|
||||
// ListWorkspaceIdentities returns durable workspace identities for relation-aware plugins.
|
||||
func (a *App) ListWorkspaceIdentities() ([]workspace.WorkspaceIdentity, string) {
|
||||
if a.workspace == nil {
|
||||
return nil, "workspace not initialized"
|
||||
}
|
||||
identities, err := a.workspace.ListWorkspaceIdentities()
|
||||
if err != nil {
|
||||
return nil, err.Error()
|
||||
}
|
||||
return identities, ""
|
||||
}
|
||||
|
||||
// RepairWorkspaceIdentity resolves a duplicated workspace marker without moving relations.
|
||||
func (a *App) RepairWorkspaceIdentity(keepName, regenerateName string) string {
|
||||
if a.workspace == nil {
|
||||
return "workspace not initialized"
|
||||
}
|
||||
if err := a.workspace.RepairWorkspaceIdentity(keepName, regenerateName); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CreateWorkspace creates a top-level physical workspace folder.
|
||||
func (a *App) CreateWorkspace(name, templateID string) (workspace.Workspace, string) {
|
||||
if a.workspace == nil {
|
||||
@@ -1961,6 +1984,7 @@ func (a *App) CreateWorkspace(name, templateID string) (workspace.Workspace, str
|
||||
}
|
||||
a.publishWorkspaceLifecycleEvent(workspaceCreatedEventName, map[string]interface{}{
|
||||
"operation": "create",
|
||||
"workspaceId": ws.ID,
|
||||
"workspaceRootPath": ws.RootPath,
|
||||
"workspaceName": ws.Name,
|
||||
"templateId": templateID,
|
||||
@@ -1976,8 +2000,13 @@ func (a *App) RenameWorkspace(oldName, newName string) string {
|
||||
if err := a.workspace.RenameWorkspace(oldName, newName); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
identity, err := a.workspace.GetWorkspaceIdentity(newName)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
a.publishWorkspaceLifecycleEvent(workspaceRenamedEventName, map[string]interface{}{
|
||||
"operation": "rename",
|
||||
"workspaceId": identity.WorkspaceID,
|
||||
"workspaceRootPath": newName,
|
||||
"workspaceName": newName,
|
||||
"previousWorkspaceRootPath": oldName,
|
||||
@@ -1997,6 +2026,7 @@ func (a *App) TrashWorkspace(name string) (workspace.TrashResult, string) {
|
||||
}
|
||||
a.publishWorkspaceLifecycleEvent(workspaceTrashedEventName, map[string]interface{}{
|
||||
"operation": "trash",
|
||||
"workspaceId": result.WorkspaceID,
|
||||
"workspaceRootPath": name,
|
||||
"workspaceName": name,
|
||||
"trashId": result.TrashID,
|
||||
|
||||
@@ -1836,6 +1836,10 @@ func TestWorkspaceAPIPublishesLifecycleEvents(t *testing.T) {
|
||||
if got := received["workspace.created"]["workspaceRootPath"]; got != "Project" {
|
||||
t.Fatalf("workspace.created workspaceRootPath = %#v, want Project", got)
|
||||
}
|
||||
createdID, _ := received["workspace.created"]["workspaceId"].(string)
|
||||
if createdID == "" {
|
||||
t.Fatal("workspace.created workspaceId is empty")
|
||||
}
|
||||
if got := received["workspace.created"]["templateId"]; got != "client-project" {
|
||||
t.Fatalf("workspace.created templateId = %#v, want client-project", got)
|
||||
}
|
||||
@@ -1845,17 +1849,48 @@ func TestWorkspaceAPIPublishesLifecycleEvents(t *testing.T) {
|
||||
if got := received["workspace.renamed"]["workspaceRootPath"]; got != "Renamed" {
|
||||
t.Fatalf("workspace.renamed workspaceRootPath = %#v, want Renamed", got)
|
||||
}
|
||||
if got := received["workspace.renamed"]["workspaceId"]; got != createdID {
|
||||
t.Fatalf("workspace.renamed workspaceId = %#v, want %q", got, createdID)
|
||||
}
|
||||
if got := received["workspace.renamed"]["previousWorkspaceRootPath"]; got != "Project" {
|
||||
t.Fatalf("workspace.renamed previousWorkspaceRootPath = %#v, want Project", got)
|
||||
}
|
||||
if got := received["workspace.trashed"]["workspaceRootPath"]; got != "Renamed" {
|
||||
t.Fatalf("workspace.trashed workspaceRootPath = %#v, want Renamed", got)
|
||||
}
|
||||
if got := received["workspace.trashed"]["workspaceId"]; got != createdID {
|
||||
t.Fatalf("workspace.trashed workspaceId = %#v, want %q", got, createdID)
|
||||
}
|
||||
if got := received["workspace.trashed"]["trashPath"]; got == "" {
|
||||
t.Fatalf("workspace.trashed trashPath = %#v, want non-empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkspaceIdentityAPIListsAndRepairsDuplicates(t *testing.T) {
|
||||
app, vaultDir := newFilesTestApp(t, []string{"files.read"})
|
||||
app.workspace = workspace.NewManager(vaultDir)
|
||||
if err := app.workspace.Load(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, errStr := app.CreateWorkspace("Original", "default"); errStr != "" {
|
||||
t.Fatalf("CreateWorkspace: %s", errStr)
|
||||
}
|
||||
identities, errStr := app.ListWorkspaceIdentities()
|
||||
if errStr != "" {
|
||||
t.Fatalf("ListWorkspaceIdentities: %s", errStr)
|
||||
}
|
||||
var original workspace.WorkspaceIdentity
|
||||
for _, identity := range identities {
|
||||
if identity.RootPath == "Original" {
|
||||
original = identity
|
||||
break
|
||||
}
|
||||
}
|
||||
if original.WorkspaceID == "" || original.State != "active" {
|
||||
t.Fatalf("identities = %+v", identities)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoveWorkspaceNodeCompatibilityIsUnsupported(t *testing.T) {
|
||||
app, vaultDir := newFilesTestApp(t, []string{"files.read"})
|
||||
app.workspace = workspace.NewManager(vaultDir)
|
||||
|
||||
Reference in New Issue
Block a user