feat: scope activity and browser links by durable workspace
This commit is contained in:
parent
fca9fff4b4
commit
6b556c59d9
|
|
@ -54,6 +54,7 @@
|
||||||
const name = workspaceName(workspace);
|
const name = workspaceName(workspace);
|
||||||
return {
|
return {
|
||||||
id: name,
|
id: name,
|
||||||
|
workspaceId: workspace?.id || workspace?.workspaceId || '',
|
||||||
type: workspace?.type || 'space',
|
type: workspace?.type || 'space',
|
||||||
title: workspace?.title || name,
|
title: workspace?.title || name,
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,12 @@ export function createPluginAPI(pluginId) {
|
||||||
return App.OpenVaultPathExternal(pluginId, relativePath);
|
return App.OpenVaultPathExternal(pluginId, relativePath);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
openURL: function(url) {
|
||||||
|
assertActive('files.openURL');
|
||||||
|
return callBackendErrorString(pluginId, 'files.openURL', function() {
|
||||||
|
return App.OpenExternalURL(pluginId, String(url == null ? '' : url));
|
||||||
|
});
|
||||||
|
},
|
||||||
showInFolder: function(relativePath) {
|
showInFolder: function(relativePath) {
|
||||||
assertActive('files.showInFolder(' + relativePath + ')');
|
assertActive('files.showInFolder(' + relativePath + ')');
|
||||||
return callBackendErrorString(pluginId, 'files.showInFolder(' + relativePath + ')', function() {
|
return callBackendErrorString(pluginId, 'files.showInFolder(' + relativePath + ')', function() {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
$: selectedWorkspace = nodes.find(n => n.id === selectedWorkspaceName || n.name === selectedWorkspaceName || n.rootPath === selectedWorkspaceName) || null;
|
$: selectedWorkspace = nodes.find(n => n.id === selectedWorkspaceName || n.name === selectedWorkspaceName || n.rootPath === selectedWorkspaceName) || null;
|
||||||
$: workspaceRootPath = selectedWorkspace?.rootPath || selectedWorkspace?.name || selectedWorkspace?.id || '';
|
$: workspaceRootPath = selectedWorkspace?.rootPath || selectedWorkspace?.name || selectedWorkspace?.id || '';
|
||||||
|
$: workspaceId = selectedWorkspace?.workspaceId || '';
|
||||||
$: workspaceTitle = selectedWorkspace?.title || selectedWorkspace?.name || selectedWorkspace?.id || selectedWorkspaceName;
|
$: workspaceTitle = selectedWorkspace?.title || selectedWorkspace?.name || selectedWorkspace?.id || selectedWorkspaceName;
|
||||||
$: workspaceType = selectedWorkspace?.type || 'workspace';
|
$: workspaceType = selectedWorkspace?.type || 'workspace';
|
||||||
$: if (workspaceRootPath !== metadataWorkspaceRoot) {
|
$: if (workspaceRootPath !== metadataWorkspaceRoot) {
|
||||||
|
|
@ -235,7 +236,7 @@
|
||||||
<PluginBundleHost
|
<PluginBundleHost
|
||||||
pluginId={activeTool.pluginId}
|
pluginId={activeTool.pluginId}
|
||||||
componentId={activeTool.component}
|
componentId={activeTool.component}
|
||||||
componentProps={{ workspaceName: selectedWorkspaceName, workspaceNodeId: selectedWorkspaceName, workspaceNode: selectedWorkspace, workspaceRootPath, toolRequest: activeToolRequest }}
|
componentProps={{ workspaceName: selectedWorkspaceName, workspaceNodeId: selectedWorkspaceName, workspaceNode: selectedWorkspace, workspaceRootPath, workspaceId, toolRequest: activeToolRequest }}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -3687,6 +3687,13 @@
|
||||||
window.__wailsMockExternalOpens = externalOpens.slice();
|
window.__wailsMockExternalOpens = externalOpens.slice();
|
||||||
return Promise.resolve('');
|
return Promise.resolve('');
|
||||||
},
|
},
|
||||||
|
OpenExternalURL: function (pluginId, rawURL) {
|
||||||
|
var err = requirePluginPermission(pluginId, 'files.openExternal');
|
||||||
|
if (err) return Promise.resolve(err);
|
||||||
|
externalOpens.push({ action: 'url', path: String(rawURL || '') });
|
||||||
|
window.__wailsMockExternalOpens = externalOpens.slice();
|
||||||
|
return Promise.resolve('');
|
||||||
|
},
|
||||||
ShowVaultPathInFolder: function (pluginId, relativePath) {
|
ShowVaultPathInFolder: function (pluginId, relativePath) {
|
||||||
var err = requirePluginPermission(pluginId, 'files.openExternal');
|
var err = requirePluginPermission(pluginId, 'files.openExternal');
|
||||||
if (err) return Promise.resolve(err);
|
if (err) return Promise.resolve(err);
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,8 @@ export function OpenVault(arg1:string):Promise<void>;
|
||||||
|
|
||||||
export function OpenVaultPathExternal(arg1:string,arg2:string):Promise<string>;
|
export function OpenVaultPathExternal(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
|
export function OpenExternalURL(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function OpenWorkbenchResource(arg1:string,arg2:Record<string, any>):Promise<workbench.OpenResourceResult|string>;
|
export function OpenWorkbenchResource(arg1:string,arg2:Record<string, any>):Promise<workbench.OpenResourceResult|string>;
|
||||||
|
|
||||||
export function PluginBrowserReceiverPairing(arg1:string):Promise<Record<string, string>|string>;
|
export function PluginBrowserReceiverPairing(arg1:string):Promise<Record<string, string>|string>;
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,10 @@ export function OpenVaultPathExternal(arg1, arg2) {
|
||||||
return window['go']['api']['App']['OpenVaultPathExternal'](arg1, arg2);
|
return window['go']['api']['App']['OpenVaultPathExternal'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function OpenExternalURL(arg1, arg2) {
|
||||||
|
return window['go']['api']['App']['OpenExternalURL'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function OpenWorkbenchResource(arg1, arg2) {
|
export function OpenWorkbenchResource(arg1, arg2) {
|
||||||
return window['go']['api']['App']['OpenWorkbenchResource'](arg1, arg2);
|
return window['go']['api']['App']['OpenWorkbenchResource'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -577,7 +577,7 @@ func (a *App) recordActivityProviderEvent(event events.Event) {
|
||||||
if _, err := a.requirePluginAccess(provider.PluginID, "storage.namespace"); err != nil {
|
if _, err := a.requirePluginAccess(provider.PluginID, "storage.namespace"); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := a.appendActivityEvent(provider.PluginID, activityFromEvent(event)); err != nil {
|
if err := a.appendActivityEvent(provider.PluginID, a.activityFromEvent(event)); err != nil {
|
||||||
log.Printf("[api] activity provider %s failed to record %s: %v", provider.PluginID, event.Name, err)
|
log.Printf("[api] activity provider %s failed to record %s: %v", provider.PluginID, event.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -622,6 +622,24 @@ func activityFromEvent(event events.Event) map[string]interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) activityFromEvent(event events.Event) map[string]interface{} {
|
||||||
|
activity := activityFromEvent(event)
|
||||||
|
workspaceRoot := firstPayloadText(activity, "workspaceRootPath")
|
||||||
|
if workspaceRoot == "" || a == nil || a.workspace == nil {
|
||||||
|
activity["sessionScope"] = map[string]interface{}{"kind": "unassigned"}
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
identity, err := a.workspace.GetWorkspaceIdentity(workspaceRoot)
|
||||||
|
if err != nil {
|
||||||
|
activity["sessionScope"] = map[string]interface{}{"kind": "unassigned"}
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
activity["workspaceId"] = identity.WorkspaceID
|
||||||
|
activity["workspaceRootPath"] = identity.RootPath
|
||||||
|
activity["sessionScope"] = map[string]interface{}{"kind": "workspace", "workspaceId": identity.WorkspaceID}
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
|
||||||
func eventPayloadMap(payload interface{}) map[string]interface{} {
|
func eventPayloadMap(payload interface{}) map[string]interface{} {
|
||||||
switch value := payload.(type) {
|
switch value := payload.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
|
|
@ -1498,6 +1516,22 @@ func (a *App) OpenVaultPathExternal(pluginID, relativePath string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenExternalURL opens an HTTP(S) URL through the platform browser opener.
|
||||||
|
// This deliberately bypasses OS file associations for InternetShortcut files.
|
||||||
|
func (a *App) OpenExternalURL(pluginID, rawURL string) string {
|
||||||
|
if _, err := a.requirePluginAccess(pluginID, "files.openExternal"); err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
parsed, err := url.ParseRequestURI(strings.TrimSpace(rawURL))
|
||||||
|
if err != nil || parsed.Host == "" || (parsed.Scheme != "http" && parsed.Scheme != "https") {
|
||||||
|
return "invalid HTTP(S) URL"
|
||||||
|
}
|
||||||
|
if err := a.externalOpenService().OpenPath(parsed.String()); err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// ShowVaultPathInFolder reveals a vault-relative file or folder in the OS file manager.
|
// ShowVaultPathInFolder reveals a vault-relative file or folder in the OS file manager.
|
||||||
func (a *App) ShowVaultPathInFolder(pluginID, relativePath string) string {
|
func (a *App) ShowVaultPathInFolder(pluginID, relativePath string) string {
|
||||||
if _, err := a.requirePluginAccess(pluginID, "files.openExternal"); err != nil {
|
if _, err := a.requirePluginAccess(pluginID, "files.openExternal"); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -823,6 +823,24 @@ func TestBrowserInboxWorkspaceReferenceSurvivesRenameAndTrash(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpenExternalURLUsesBrowserOpenService(t *testing.T) {
|
||||||
|
app, _ := newFilesTestApp(t, []string{"files.openExternal"})
|
||||||
|
opened := ""
|
||||||
|
app.externalOpen = newTestExternalOpenService(func(path string) error {
|
||||||
|
opened = path
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if errStr := app.OpenExternalURL("files.plugin", "https://example.com/path"); errStr != "" {
|
||||||
|
t.Fatalf("OpenExternalURL: %s", errStr)
|
||||||
|
}
|
||||||
|
if opened != "https://example.com/path" {
|
||||||
|
t.Fatalf("opened = %q, want URL", opened)
|
||||||
|
}
|
||||||
|
if errStr := app.OpenExternalURL("files.plugin", "ftp://example.com"); errStr == "" {
|
||||||
|
t.Fatal("OpenExternalURL accepted unsupported URL scheme")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBrowserInboxRejectsCaptureWithoutOpenVault(t *testing.T) {
|
func TestBrowserInboxRejectsCaptureWithoutOpenVault(t *testing.T) {
|
||||||
v := vault.NewVault(nil)
|
v := vault.NewVault(nil)
|
||||||
app := &App{
|
app := &App{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue