@eclipse-lyra/core 0.7.14 → 0.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.js +17 -13
- package/dist/api/services.d.ts +1 -0
- package/dist/api/services.d.ts.map +1 -1
- package/dist/{config-C8viItpG.js → config-CTHJsmbF.js} +16 -6
- package/dist/config-CTHJsmbF.js.map +1 -0
- package/dist/core/apploader.d.ts +6 -0
- package/dist/core/apploader.d.ts.map +1 -1
- package/dist/core/contribution-mapping.d.ts +68 -0
- package/dist/core/contribution-mapping.d.ts.map +1 -0
- package/dist/core/contributionregistry.d.ts +12 -0
- package/dist/core/contributionregistry.d.ts.map +1 -1
- package/dist/core/ui-ids.d.ts +11 -0
- package/dist/core/ui-ids.d.ts.map +1 -0
- package/dist/{icon-DN6fp0dg.js → icon-C3H7IMWU.js} +135 -14
- package/dist/icon-C3H7IMWU.js.map +1 -0
- package/dist/index.js +17 -13
- package/dist/{nocontent-BhrN6yxJ.js → nocontent-TgnGDnXO.js} +2 -2
- package/dist/{nocontent-BhrN6yxJ.js.map → nocontent-TgnGDnXO.js.map} +1 -1
- package/dist/parts/index.js +1 -1
- package/dist/{resizable-grid-CIgUY5TR.js → resizable-grid-B6j8J49V.js} +13 -2
- package/dist/resizable-grid-B6j8J49V.js.map +1 -0
- package/dist/widgets/index.js +2 -2
- package/package.json +1 -1
- package/src/api/services.ts +6 -0
- package/src/contributions/default-ui-contributions.ts +14 -2
- package/src/core/apploader.ts +28 -7
- package/src/core/contribution-mapping.ts +142 -0
- package/src/core/contributionregistry.ts +44 -8
- package/src/core/ui-ids.ts +14 -0
- package/dist/config-C8viItpG.js.map +0 -1
- package/dist/icon-DN6fp0dg.js.map +0 -1
- package/dist/resizable-grid-CIgUY5TR.js.map +0 -1
package/dist/widgets/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "../nocontent-
|
|
2
|
-
import "../icon-
|
|
1
|
+
import "../nocontent-TgnGDnXO.js";
|
|
2
|
+
import "../icon-C3H7IMWU.js";
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/src/api/services.ts
CHANGED
|
@@ -51,4 +51,10 @@ export { persistenceService } from '../core/persistenceservice';
|
|
|
51
51
|
export { esmShService } from '../core/esmsh-service';
|
|
52
52
|
export type { EsmShSource, EsmShOptions } from '../core/esmsh-service';
|
|
53
53
|
export { i18nLazy, i18n, SYSTEM_LANGUAGE_BUNDLES } from '../core/i18n';
|
|
54
|
+
export {
|
|
55
|
+
contributionTargetMappingRegistry,
|
|
56
|
+
overrideContributionTargets,
|
|
57
|
+
applyConfigNameRemaps,
|
|
58
|
+
listContributionNameRemaps
|
|
59
|
+
} from '../core/contribution-mapping';
|
|
54
60
|
|
|
@@ -5,22 +5,31 @@ import {
|
|
|
5
5
|
TOOLBAR_BOTTOM_END,
|
|
6
6
|
TOOLBAR_MAIN_RIGHT
|
|
7
7
|
} from "../core/constants";
|
|
8
|
+
import {
|
|
9
|
+
VIEW_FILEBROWSER,
|
|
10
|
+
VIEW_LOG_TERMINAL,
|
|
11
|
+
TOOLBAR_APP_SWITCHER,
|
|
12
|
+
TOOLBAR_FAST_VIEWS,
|
|
13
|
+
TOOLBAR_INFO,
|
|
14
|
+
TOOLBAR_LANGUAGE_SELECTOR
|
|
15
|
+
} from "../core/ui-ids";
|
|
8
16
|
|
|
9
17
|
contributionRegistry.registerContribution(SIDEBAR_MAIN, {
|
|
10
|
-
name:
|
|
18
|
+
name: VIEW_FILEBROWSER,
|
|
11
19
|
label: "Workspace",
|
|
12
20
|
icon: "folder-open",
|
|
13
21
|
component: (id: string) => html`<lyra-filebrowser id="${id}"></lyra-filebrowser>`
|
|
14
22
|
});
|
|
15
23
|
|
|
16
24
|
contributionRegistry.registerContribution("system.fastviews-bottomend", {
|
|
17
|
-
name:
|
|
25
|
+
name: VIEW_LOG_TERMINAL,
|
|
18
26
|
label: "Log Messages",
|
|
19
27
|
icon: "list",
|
|
20
28
|
component: (id: string) => html`<lyra-log-terminal id="${id}"></lyra-log-terminal>`
|
|
21
29
|
});
|
|
22
30
|
|
|
23
31
|
contributionRegistry.registerContribution(TOOLBAR_BOTTOM_END, {
|
|
32
|
+
name: TOOLBAR_INFO,
|
|
24
33
|
label: "Info",
|
|
25
34
|
icon: "circle-info",
|
|
26
35
|
command: "show_version_info",
|
|
@@ -28,16 +37,19 @@ contributionRegistry.registerContribution(TOOLBAR_BOTTOM_END, {
|
|
|
28
37
|
});
|
|
29
38
|
|
|
30
39
|
contributionRegistry.registerContribution(TOOLBAR_BOTTOM_END, {
|
|
40
|
+
name: TOOLBAR_FAST_VIEWS,
|
|
31
41
|
label: `Fast Views`,
|
|
32
42
|
component: `<lyra-fastviews target="system.fastviews-bottomend" icon="bolt" title="Fast Views"></lyra-fastviews>`
|
|
33
43
|
});
|
|
34
44
|
|
|
35
45
|
contributionRegistry.registerContribution(TOOLBAR_BOTTOM_END, {
|
|
46
|
+
name: TOOLBAR_LANGUAGE_SELECTOR,
|
|
36
47
|
label: "Language",
|
|
37
48
|
component: () => html`<lyra-language-selector></lyra-language-selector>`
|
|
38
49
|
});
|
|
39
50
|
|
|
40
51
|
contributionRegistry.registerContribution(TOOLBAR_MAIN_RIGHT, {
|
|
52
|
+
name: TOOLBAR_APP_SWITCHER,
|
|
41
53
|
label: "App Switcher",
|
|
42
54
|
component: () => html`<lyra-layout-switcher></lyra-layout-switcher>`
|
|
43
55
|
} as HTMLContribution);
|
package/src/core/apploader.ts
CHANGED
|
@@ -12,14 +12,16 @@
|
|
|
12
12
|
* - App Loader: Bridge between framework and application
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import {render, TemplateResult, html} from "lit";
|
|
16
|
-
import {rootContext} from "./di";
|
|
17
|
-
import {createLogger} from "./logger";
|
|
18
|
-
import {extensionRegistry, Extension} from "./extensionregistry";
|
|
19
|
-
import {contributionRegistry, Contribution, LayoutContribution} from "./contributionregistry";
|
|
20
|
-
import {SYSTEM_LAYOUTS} from "./constants";
|
|
21
|
-
import {appSettings} from "./settingsservice";
|
|
15
|
+
import { render, TemplateResult, html } from "lit";
|
|
16
|
+
import { rootContext } from "./di";
|
|
17
|
+
import { createLogger } from "./logger";
|
|
18
|
+
import { extensionRegistry, Extension } from "./extensionregistry";
|
|
19
|
+
import { contributionRegistry, Contribution, LayoutContribution, TOPIC_CONTRIBUTEIONS_CHANGED } from "./contributionregistry";
|
|
20
|
+
import { SYSTEM_LAYOUTS } from "./constants";
|
|
21
|
+
import { appSettings } from "./settingsservice";
|
|
22
22
|
import { marketplaceRegistry } from "./marketplaceregistry";
|
|
23
|
+
import { contributionTargetMappingRegistry, type ContributionNameRemap } from "./contribution-mapping";
|
|
24
|
+
import { publish } from "./events";
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
const logger = createLogger('AppLoader');
|
|
@@ -209,6 +211,12 @@ export interface AppDefinition {
|
|
|
209
211
|
|
|
210
212
|
/** Marketplace catalog URLs for this app. Registered when the app is registered. */
|
|
211
213
|
marketplaceCatalogUrls?: string[];
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Optional contribution remaps for this application.
|
|
217
|
+
* Allows apps to declaratively remap contributions to different targets.
|
|
218
|
+
*/
|
|
219
|
+
remaps?: ContributionNameRemap[];
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
/**
|
|
@@ -451,6 +459,19 @@ class AppLoaderService {
|
|
|
451
459
|
}
|
|
452
460
|
}
|
|
453
461
|
|
|
462
|
+
// Apply app-level contribution remaps before registering contributions
|
|
463
|
+
contributionTargetMappingRegistry.applyAppNameRemaps(app.remaps);
|
|
464
|
+
if (app.remaps?.length) {
|
|
465
|
+
const remappedTargets = new Set<string>();
|
|
466
|
+
for (const r of app.remaps) {
|
|
467
|
+
for (const t of r.targets) remappedTargets.add(t);
|
|
468
|
+
}
|
|
469
|
+
for (const target of remappedTargets) {
|
|
470
|
+
const contributions = contributionRegistry.getContributions(target);
|
|
471
|
+
publish(TOPIC_CONTRIBUTEIONS_CHANGED, { target, contributions });
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
454
475
|
// Register app contributions
|
|
455
476
|
if (app.contributions) {
|
|
456
477
|
logger.info('Registering app contributions...');
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { rootContext } from "./di";
|
|
2
|
+
import type { Contribution } from "./contributionregistry";
|
|
3
|
+
|
|
4
|
+
export interface ContributionNameRemap {
|
|
5
|
+
/**
|
|
6
|
+
* Globally unique, namespaced contribution name
|
|
7
|
+
* (e.g. "view.filebrowser", "toolbar.filebrowser.rename").
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* Effective target slots for this contribution.
|
|
12
|
+
* If empty, the original target is used.
|
|
13
|
+
*/
|
|
14
|
+
targets: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface NameRemapState {
|
|
18
|
+
appTargets: string[] | undefined;
|
|
19
|
+
globalTargets: string[] | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Registry responsible for resolving effective contribution targets.
|
|
24
|
+
*
|
|
25
|
+
* It supports:
|
|
26
|
+
* - Global (framework-level) remaps.
|
|
27
|
+
* - App-level remaps coming from AppDefinition.
|
|
28
|
+
* - Multiple targets per contribution.
|
|
29
|
+
*
|
|
30
|
+
* Resolution precedence:
|
|
31
|
+
* app-level remap > global remap > original target
|
|
32
|
+
*/
|
|
33
|
+
class ContributionTargetMappingRegistry {
|
|
34
|
+
private globalNameRemaps = new Map<string, string[]>();
|
|
35
|
+
private appNameRemaps = new Map<string, string[]>();
|
|
36
|
+
|
|
37
|
+
setGlobalNameRemap(name: string, targets: string[]): void {
|
|
38
|
+
this.globalNameRemaps.set(name, this.normalizeTargets(targets));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Clears all remaps. For testing only. */
|
|
42
|
+
resetForTesting(): void {
|
|
43
|
+
this.globalNameRemaps.clear();
|
|
44
|
+
this.appNameRemaps.clear();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
applyAppNameRemaps(remaps: ContributionNameRemap[] | undefined | null): void {
|
|
48
|
+
this.appNameRemaps.clear();
|
|
49
|
+
if (!remaps) return;
|
|
50
|
+
for (const remap of remaps) {
|
|
51
|
+
this.appNameRemaps.set(remap.name, this.normalizeTargets(remap.targets));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the effective target slots for a contribution given its original target.
|
|
57
|
+
*
|
|
58
|
+
* Semantics:
|
|
59
|
+
* - When a remap exists with a non-empty targets array, those targets are used.
|
|
60
|
+
* - When a remap exists with an empty targets array, the contribution is disabled (no targets).
|
|
61
|
+
* - When no remap exists, the original target is used.
|
|
62
|
+
*/
|
|
63
|
+
getEffectiveTargets(originalTarget: string, contribution: Contribution): string[] {
|
|
64
|
+
const name = (contribution as any).name as string | undefined;
|
|
65
|
+
if (!name) {
|
|
66
|
+
return [originalTarget];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const appTargets = this.appNameRemaps.get(name);
|
|
70
|
+
if (appTargets) {
|
|
71
|
+
return appTargets.length > 0 ? appTargets : [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const globalTargets = this.globalNameRemaps.get(name);
|
|
75
|
+
if (globalTargets) {
|
|
76
|
+
return globalTargets.length > 0 ? globalTargets : [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return [originalTarget];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns current mapping state for debugging and tooling.
|
|
84
|
+
*/
|
|
85
|
+
listNameRemaps(): Record<string, NameRemapState> {
|
|
86
|
+
const result: Record<string, NameRemapState> = {};
|
|
87
|
+
const allNames = new Set<string>([
|
|
88
|
+
...this.globalNameRemaps.keys(),
|
|
89
|
+
...this.appNameRemaps.keys()
|
|
90
|
+
]);
|
|
91
|
+
for (const name of allNames) {
|
|
92
|
+
result[name] = {
|
|
93
|
+
appTargets: this.appNameRemaps.get(name),
|
|
94
|
+
globalTargets: this.globalNameRemaps.get(name)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private normalizeTargets(targets: string[]): string[] {
|
|
101
|
+
const seen = new Set<string>();
|
|
102
|
+
const result: string[] = [];
|
|
103
|
+
for (const t of targets) {
|
|
104
|
+
if (!t || seen.has(t)) continue;
|
|
105
|
+
seen.add(t);
|
|
106
|
+
result.push(t);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const contributionTargetMappingRegistry = new ContributionTargetMappingRegistry();
|
|
113
|
+
rootContext.put("contributionTargetMappingRegistry", contributionTargetMappingRegistry);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Public helper to override contribution targets programmatically.
|
|
117
|
+
* This sets a global remap that applies across all apps.
|
|
118
|
+
*/
|
|
119
|
+
export function overrideContributionTargets(name: string, targets: string | string[]): void {
|
|
120
|
+
const normalized = Array.isArray(targets) ? targets : [targets];
|
|
121
|
+
contributionTargetMappingRegistry.setGlobalNameRemap(name, normalized);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Apply config-driven name remaps from a simple object.
|
|
126
|
+
* Intended for hosts that want to load JSON/YAML mapping files.
|
|
127
|
+
*/
|
|
128
|
+
export function applyConfigNameRemaps(config: Record<string, string | string[]>): void {
|
|
129
|
+
for (const [name, targets] of Object.entries(config)) {
|
|
130
|
+
const normalized = Array.isArray(targets) ? targets : [targets];
|
|
131
|
+
contributionTargetMappingRegistry.setGlobalNameRemap(name, normalized);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Convenience helper for debugging: returns current remap state
|
|
137
|
+
* for all known contribution names.
|
|
138
|
+
*/
|
|
139
|
+
export function listContributionNameRemaps(): Record<string, NameRemapState> {
|
|
140
|
+
return contributionTargetMappingRegistry.listNameRemaps();
|
|
141
|
+
}
|
|
142
|
+
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {Signal} from "@lit-labs/signals";
|
|
2
|
-
import {TemplateResult} from "lit";
|
|
3
|
-
import {publish} from "./events";
|
|
4
|
-
import {rootContext} from "./di";
|
|
1
|
+
import { Signal } from "@lit-labs/signals";
|
|
2
|
+
import { TemplateResult } from "lit";
|
|
3
|
+
import { publish } from "./events";
|
|
4
|
+
import { rootContext } from "./di";
|
|
5
|
+
import { contributionTargetMappingRegistry } from "./contribution-mapping";
|
|
5
6
|
|
|
6
7
|
export const TOPIC_CONTRIBUTEIONS_CHANGED = "events/contributionregistry/contributionsChanged"
|
|
7
8
|
|
|
@@ -11,6 +12,8 @@ export interface ContributionChangeEvent {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export interface Contribution {
|
|
15
|
+
/** Optional globally unique, namespaced contribution name (e.g. "view.filebrowser"). */
|
|
16
|
+
name?: string;
|
|
14
17
|
target?: string;
|
|
15
18
|
label: string;
|
|
16
19
|
icon?: string;
|
|
@@ -58,7 +61,7 @@ class ContributionRegistry {
|
|
|
58
61
|
private contributions: Map<string, Contribution[]> = new Map();
|
|
59
62
|
|
|
60
63
|
registerContribution<T extends Contribution>(target: string, contribution: T) {
|
|
61
|
-
const targetSlot = this.
|
|
64
|
+
const targetSlot = this.getOrCreateSlot(target);
|
|
62
65
|
if ("command" in contribution) {
|
|
63
66
|
const cmd = contribution as unknown as CommandContribution
|
|
64
67
|
if (cmd.disabled instanceof Function) {
|
|
@@ -66,14 +69,47 @@ class ContributionRegistry {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
targetSlot.push(contribution);
|
|
69
|
-
publish(TOPIC_CONTRIBUTEIONS_CHANGED, { target, contributions: targetSlot } as ContributionChangeEvent)
|
|
72
|
+
publish(TOPIC_CONTRIBUTEIONS_CHANGED, { target, contributions: targetSlot } as ContributionChangeEvent);
|
|
73
|
+
|
|
74
|
+
const effectiveTargets = contributionTargetMappingRegistry.getEffectiveTargets(target, contribution);
|
|
75
|
+
for (const effectiveTarget of effectiveTargets) {
|
|
76
|
+
if (effectiveTarget === target) continue;
|
|
77
|
+
const contributionsForSlot = this.getContributions(effectiveTarget);
|
|
78
|
+
publish(TOPIC_CONTRIBUTEIONS_CHANGED, { target: effectiveTarget, contributions: contributionsForSlot } as ContributionChangeEvent);
|
|
79
|
+
}
|
|
70
80
|
}
|
|
71
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Returns all contributions whose *effective* targets include the given slot.
|
|
84
|
+
*
|
|
85
|
+
* Note: This currently scans all registered contributions and resolves
|
|
86
|
+
* remaps on each call (O(N) in number of contributions). This is acceptable
|
|
87
|
+
* for typical Lyra apps (dozens/hundreds of contributions and few slots),
|
|
88
|
+
* but if contribution counts grow significantly we may want to introduce a
|
|
89
|
+
* cached index of effective targets per slot to keep lookups O(1).
|
|
90
|
+
*/
|
|
72
91
|
getContributions<T extends Contribution>(target: string): T[] {
|
|
92
|
+
const results: T[] = [];
|
|
93
|
+
for (const [originalTarget, list] of this.contributions.entries()) {
|
|
94
|
+
const typedList = list as T[];
|
|
95
|
+
for (const contribution of typedList) {
|
|
96
|
+
const effectiveTargets = contributionTargetMappingRegistry.getEffectiveTargets(originalTarget, contribution);
|
|
97
|
+
if (effectiveTargets.includes(target)) {
|
|
98
|
+
results.push(contribution);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (results.length === 0) {
|
|
103
|
+
this.getOrCreateSlot(target);
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getOrCreateSlot(target: string): Contribution[] {
|
|
73
109
|
if (!this.contributions.has(target)) {
|
|
74
|
-
this.contributions.set(target, [])
|
|
110
|
+
this.contributions.set(target, []);
|
|
75
111
|
}
|
|
76
|
-
return this.contributions.get(target)
|
|
112
|
+
return this.contributions.get(target)!;
|
|
77
113
|
}
|
|
78
114
|
}
|
|
79
115
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const VIEW_FILEBROWSER = "view.filebrowser";
|
|
2
|
+
export const VIEW_LOG_TERMINAL = "view.logTerminal";
|
|
3
|
+
|
|
4
|
+
export const TOOLBAR_INFO = "toolbar.info";
|
|
5
|
+
export const TOOLBAR_FAST_VIEWS = "toolbar.fastViews";
|
|
6
|
+
export const TOOLBAR_LANGUAGE_SELECTOR = "toolbar.languageSelector";
|
|
7
|
+
export const TOOLBAR_APP_SWITCHER = "toolbar.appSwitcher";
|
|
8
|
+
|
|
9
|
+
export const TOOLBAR_FILEBROWSER_RENAME = "toolbar.filebrowser.rename";
|
|
10
|
+
export const TOOLBAR_FILEBROWSER_DELETE = "toolbar.filebrowser.delete";
|
|
11
|
+
|
|
12
|
+
export const CTXMENU_FILEBROWSER_RENAME = "contextmenu.filebrowser.rename";
|
|
13
|
+
export const CTXMENU_FILEBROWSER_DELETE = "contextmenu.filebrowser.delete";
|
|
14
|
+
|