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);
|
||||
return {
|
||||
id: name,
|
||||
workspaceId: workspace?.id || workspace?.workspaceId || '',
|
||||
type: workspace?.type || 'space',
|
||||
title: workspace?.title || name,
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -429,6 +429,12 @@ export function createPluginAPI(pluginId) {
|
|||
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) {
|
||||
assertActive('files.showInFolder(' + relativePath + ')');
|
||||
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;
|
||||
$: workspaceRootPath = selectedWorkspace?.rootPath || selectedWorkspace?.name || selectedWorkspace?.id || '';
|
||||
$: workspaceId = selectedWorkspace?.workspaceId || '';
|
||||
$: workspaceTitle = selectedWorkspace?.title || selectedWorkspace?.name || selectedWorkspace?.id || selectedWorkspaceName;
|
||||
$: workspaceType = selectedWorkspace?.type || 'workspace';
|
||||
$: if (workspaceRootPath !== metadataWorkspaceRoot) {
|
||||
|
|
@ -235,7 +236,7 @@
|
|||
<PluginBundleHost
|
||||
pluginId={activeTool.pluginId}
|
||||
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}
|
||||
|
|
|
|||
|
|
@ -3687,6 +3687,13 @@
|
|||
window.__wailsMockExternalOpens = externalOpens.slice();
|
||||
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) {
|
||||
var err = requirePluginPermission(pluginId, 'files.openExternal');
|
||||
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 OpenExternalURL(arg1:string,arg2:string):Promise<string>;
|
||||
|
||||
export function OpenWorkbenchResource(arg1:string,arg2:Record<string, any>):Promise<workbench.OpenResourceResult|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);
|
||||
}
|
||||
|
||||
export function OpenExternalURL(arg1, arg2) {
|
||||
return window['go']['api']['App']['OpenExternalURL'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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{} {
|
||||
switch value := payload.(type) {
|
||||
case map[string]interface{}:
|
||||
|
|
@ -1498,6 +1516,22 @@ func (a *App) OpenVaultPathExternal(pluginID, relativePath string) string {
|
|||
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.
|
||||
func (a *App) ShowVaultPathInFolder(pluginID, relativePath string) string {
|
||||
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) {
|
||||
v := vault.NewVault(nil)
|
||||
app := &App{
|
||||
|
|
|
|||
Loading…
Reference in New Issue