@eclipse-lyra/core 0.7.5 → 0.7.7
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 +28 -29
- package/dist/api/services.d.ts +0 -4
- package/dist/api/services.d.ts.map +1 -1
- package/dist/api/types.d.ts +1 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/components/fastviews.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/{app-switcher.d.ts → layout-switcher.d.ts} +5 -4
- package/dist/components/layout-switcher.d.ts.map +1 -0
- package/dist/{standard-layout-BSGa06lP.js → config-BiRvaEoO.js} +251 -462
- package/dist/config-BiRvaEoO.js.map +1 -0
- package/dist/contributions/default-layout-contributions.d.ts +1 -0
- package/dist/contributions/default-layout-contributions.d.ts.map +1 -0
- package/dist/contributions/index.d.ts.map +1 -1
- package/dist/core/apploader.d.ts +40 -30
- package/dist/core/apploader.d.ts.map +1 -1
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/contributionregistry.d.ts +10 -9
- package/dist/core/contributionregistry.d.ts.map +1 -1
- package/dist/core/editorregistry.d.ts +1 -1
- package/dist/core/editorregistry.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/icon-DN6fp0dg.js.map +1 -1
- package/dist/index.js +28 -29
- package/dist/parts/contextmenu.d.ts +1 -1
- package/dist/parts/index.js +1 -1
- package/dist/parts/resizable-grid.d.ts +1 -1
- package/dist/{resizable-grid-BRH3MyZK.js → resizable-grid-oWYRVx30.js} +322 -101
- package/dist/resizable-grid-oWYRVx30.js.map +1 -0
- package/dist/vite-plugin-resolve-deps.d.ts +18 -0
- package/dist/vite-plugin-resolve-deps.d.ts.map +1 -0
- package/dist/widgets/icon.d.ts +1 -1
- package/package.json +8 -1
- package/src/api/services.ts +0 -4
- package/src/api/types.ts +1 -1
- package/src/commands/global.ts +1 -1
- package/src/commands/version-info.ts +24 -10
- package/src/components/command.ts +2 -2
- package/src/components/index.ts +1 -1
- package/src/components/layout-switcher.ts +83 -0
- package/src/components/part-name.ts +1 -1
- package/src/components/tasks.ts +1 -1
- package/src/contributions/default-layout-contributions.ts +10 -0
- package/src/contributions/default-ui-contributions.ts +3 -3
- package/src/contributions/index.ts +1 -0
- package/src/contributions/marketplace-catalog-contributions.ts +1 -1
- package/src/core/apploader.ts +182 -99
- package/src/core/constants.ts +1 -0
- package/src/core/contributionregistry.ts +8 -10
- package/src/core/editorregistry.ts +4 -4
- package/src/core/index.ts +0 -1
- package/src/parts/contextmenu.ts +2 -2
- package/src/parts/toolbar.ts +3 -3
- package/src/vite-env.d.ts +9 -0
- package/src/vite-plugin-resolve-deps.ts +112 -0
- package/dist/components/app-selector.d.ts +0 -17
- package/dist/components/app-selector.d.ts.map +0 -1
- package/dist/components/app-switcher.d.ts.map +0 -1
- package/dist/core/app-host-config.d.ts +0 -7
- package/dist/core/app-host-config.d.ts.map +0 -1
- package/dist/core/packageinfoservice.d.ts +0 -16
- package/dist/core/packageinfoservice.d.ts.map +0 -1
- package/dist/resizable-grid-BRH3MyZK.js.map +0 -1
- package/dist/standard-layout-BSGa06lP.js.map +0 -1
- package/src/components/app-selector.ts +0 -233
- package/src/components/app-switcher.ts +0 -126
- package/src/core/app-host-config.ts +0 -23
- package/src/core/packageinfoservice.ts +0 -56
package/src/core/apploader.ts
CHANGED
|
@@ -16,8 +16,10 @@ import {render, TemplateResult, html} from "lit";
|
|
|
16
16
|
import {rootContext} from "./di";
|
|
17
17
|
import {createLogger} from "./logger";
|
|
18
18
|
import {extensionRegistry, Extension} from "./extensionregistry";
|
|
19
|
-
import {contributionRegistry, Contribution} from "./contributionregistry";
|
|
19
|
+
import {contributionRegistry, Contribution, LayoutContribution} from "./contributionregistry";
|
|
20
|
+
import {SYSTEM_LAYOUTS} from "./constants";
|
|
20
21
|
import {appSettings} from "./settingsservice";
|
|
22
|
+
import { marketplaceRegistry } from "./marketplaceregistry";
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
const logger = createLogger('AppLoader');
|
|
@@ -122,17 +124,17 @@ export interface RenderDescriptor {
|
|
|
122
124
|
* Applications implement this interface to integrate with the framework.
|
|
123
125
|
*/
|
|
124
126
|
export interface AppDefinition {
|
|
125
|
-
/** Unique
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/** Application
|
|
132
|
-
version: string;
|
|
133
|
-
|
|
134
|
-
/** Optional application description */
|
|
127
|
+
/** Application name (from package.json). Unique key; set by hostConfig resolution when omitted. */
|
|
128
|
+
name?: string;
|
|
129
|
+
|
|
130
|
+
/** Application version. Set by hostConfig resolution from package.json when omitted. */
|
|
131
|
+
version?: string;
|
|
132
|
+
|
|
133
|
+
/** Application description. Set by hostConfig resolution from package.json when omitted. */
|
|
135
134
|
description?: string;
|
|
135
|
+
|
|
136
|
+
/** Optional URL path segment for routing (e.g. "geospace"). When absent, name is used for lookup. */
|
|
137
|
+
path?: string;
|
|
136
138
|
|
|
137
139
|
/**
|
|
138
140
|
* Custom application metadata (optional).
|
|
@@ -168,32 +170,32 @@ export interface AppDefinition {
|
|
|
168
170
|
* (if metadata.github is configured).
|
|
169
171
|
*/
|
|
170
172
|
releaseHistory?: ReleaseHistory | (() => ReleaseHistory | Promise<ReleaseHistory>);
|
|
171
|
-
|
|
173
|
+
|
|
172
174
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* - A descriptor { tag, attributes? } for a single custom element with optional attributes.
|
|
176
|
-
* - A function returning a Lit TemplateResult for custom templates (requires lit in the app).
|
|
177
|
-
* If not provided, defaults to lyra-standard-layout.
|
|
175
|
+
* Id of a layout registered to the system.layouts contribution slot.
|
|
176
|
+
* The app root is always the chosen layout's component. Defaults to 'standard' when omitted.
|
|
178
177
|
*/
|
|
179
|
-
|
|
178
|
+
layoutId?: string;
|
|
180
179
|
|
|
181
180
|
/**
|
|
182
181
|
* Optional cleanup function.
|
|
183
182
|
* Called when the app is being unloaded, before extensions are disabled.
|
|
184
183
|
*/
|
|
185
184
|
dispose?: () => void | Promise<void>;
|
|
185
|
+
|
|
186
|
+
/** Resolved dependency versions (e.g. from build plugin). Shown in About / version info. */
|
|
187
|
+
dependencies?: Record<string, string>;
|
|
188
|
+
|
|
189
|
+
/** Marketplace catalog URLs for this app. Registered when the app is registered. */
|
|
190
|
+
marketplaceCatalogUrls?: string[];
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
/**
|
|
189
194
|
* Options for registering an application with the apploader.
|
|
190
195
|
*/
|
|
191
196
|
export interface RegisterAppOptions {
|
|
192
|
-
/**
|
|
193
|
-
|
|
194
|
-
* If not specified, the first registered app will be loaded.
|
|
195
|
-
*/
|
|
196
|
-
defaultAppId?: string;
|
|
197
|
+
/** Default app name to load if no app URL parameter is provided. If not specified, the first registered app is loaded. */
|
|
198
|
+
defaultAppName?: string;
|
|
197
199
|
|
|
198
200
|
/**
|
|
199
201
|
* Whether to automatically start the apploader after registration.
|
|
@@ -207,6 +209,11 @@ export interface RegisterAppOptions {
|
|
|
207
209
|
* Defaults to document.body.
|
|
208
210
|
*/
|
|
209
211
|
container?: HTMLElement;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* When true, fill name, version, description, dependencies, marketplaceCatalogUrls from __RESOLVED_PACKAGE_INFO__ only when not already set on the app.
|
|
215
|
+
*/
|
|
216
|
+
hostConfig?: boolean;
|
|
210
217
|
}
|
|
211
218
|
|
|
212
219
|
/**
|
|
@@ -222,10 +229,12 @@ class AppLoaderService {
|
|
|
222
229
|
private apps: Map<string, AppDefinition> = new Map();
|
|
223
230
|
private currentApp?: AppDefinition;
|
|
224
231
|
private started: boolean = false;
|
|
225
|
-
private
|
|
232
|
+
private defaultAppName?: string;
|
|
226
233
|
private container: HTMLElement = document.body;
|
|
227
234
|
private systemRequiredExtensions: Set<string> = new Set();
|
|
228
|
-
private static readonly PREFERRED_APP_KEY = '
|
|
235
|
+
private static readonly PREFERRED_APP_KEY = 'preferredAppName';
|
|
236
|
+
private static readonly PREFERRED_LAYOUT_KEY = 'preferredLayoutId';
|
|
237
|
+
private preferredLayoutId?: string;
|
|
229
238
|
|
|
230
239
|
/**
|
|
231
240
|
* Register an application with the framework.
|
|
@@ -235,15 +244,29 @@ class AppLoaderService {
|
|
|
235
244
|
* @param options - Optional configuration for registration and auto-starting
|
|
236
245
|
*/
|
|
237
246
|
registerApp(app: AppDefinition, options?: RegisterAppOptions): void {
|
|
238
|
-
if (
|
|
239
|
-
|
|
247
|
+
if (options?.hostConfig === true && typeof __RESOLVED_PACKAGE_INFO__ !== 'undefined') {
|
|
248
|
+
const resolved = __RESOLVED_PACKAGE_INFO__;
|
|
249
|
+
if (app.name === undefined) app.name = resolved.name;
|
|
250
|
+
if (app.version === undefined) app.version = resolved.version;
|
|
251
|
+
if (app.description === undefined) app.description = resolved.description;
|
|
252
|
+
if (app.dependencies === undefined) app.dependencies = resolved.dependencies;
|
|
253
|
+
if (app.marketplaceCatalogUrls === undefined) app.marketplaceCatalogUrls = resolved.marketplaceCatalogUrls;
|
|
240
254
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
255
|
+
app.name = app.name ?? 'app';
|
|
256
|
+
app.version = app.version ?? '0.0.0';
|
|
257
|
+
|
|
258
|
+
if (this.apps.has(app.name)) {
|
|
259
|
+
logger.warn(`App '${app.name}' is already registered. Overwriting.`);
|
|
260
|
+
}
|
|
261
|
+
if (app.marketplaceCatalogUrls?.length) {
|
|
262
|
+
app.marketplaceCatalogUrls.forEach((url) => marketplaceRegistry.addCatalogUrl(url).catch(() => {}));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this.apps.set(app.name, app);
|
|
266
|
+
logger.info(`Registered app: ${app.name} v${app.version}`);
|
|
267
|
+
|
|
268
|
+
if (options?.defaultAppName) {
|
|
269
|
+
this.defaultAppName = options.defaultAppName;
|
|
247
270
|
}
|
|
248
271
|
|
|
249
272
|
if (options?.container) {
|
|
@@ -279,11 +302,10 @@ class AppLoaderService {
|
|
|
279
302
|
|
|
280
303
|
const app = module.default as AppDefinition;
|
|
281
304
|
|
|
282
|
-
if (!app.
|
|
283
|
-
throw new Error(`Module at ${url} does not export a valid AppDefinition`);
|
|
305
|
+
if (!app.name || !app.version) {
|
|
306
|
+
throw new Error(`Module at ${url} does not export a valid AppDefinition (name and version required)`);
|
|
284
307
|
}
|
|
285
|
-
|
|
286
|
-
logger.info(`Successfully loaded app definition from URL: ${app.name} (${app.id})`);
|
|
308
|
+
logger.info(`Successfully loaded app definition from URL: ${app.name}`);
|
|
287
309
|
return app;
|
|
288
310
|
} catch (error) {
|
|
289
311
|
logger.error(`Failed to load app from URL ${url}: ${getErrorMessage(error)}`);
|
|
@@ -294,7 +316,7 @@ class AppLoaderService {
|
|
|
294
316
|
/**
|
|
295
317
|
* Start the application loader.
|
|
296
318
|
* Checks URL parameters for app=URL, loads that extension or app if found.
|
|
297
|
-
* URL parameter has higher precedence than
|
|
319
|
+
* URL parameter has higher precedence than defaultAppName.
|
|
298
320
|
* Then loads the default app or first registered app.
|
|
299
321
|
* This method is idempotent - calling it multiple times only starts once.
|
|
300
322
|
*/
|
|
@@ -338,7 +360,8 @@ class AppLoaderService {
|
|
|
338
360
|
try {
|
|
339
361
|
const app = await this.loadAppFromUrl(appUrl);
|
|
340
362
|
this.registerApp(app);
|
|
341
|
-
|
|
363
|
+
if (!app.name) throw new Error('App from URL has no name after registration');
|
|
364
|
+
await this.loadApp(app.name, this.container);
|
|
342
365
|
logger.info(`Successfully loaded app from URL: ${appUrl}`);
|
|
343
366
|
return;
|
|
344
367
|
} catch (appError) {
|
|
@@ -365,17 +388,26 @@ class AppLoaderService {
|
|
|
365
388
|
await this.loadApp(appToLoad, this.container);
|
|
366
389
|
}
|
|
367
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Resolve a path/URL segment to an app name (map key). Matches app.path, app.name, or name ending with /segment.
|
|
393
|
+
*/
|
|
394
|
+
private findAppNameBySegment(segment: string): string | undefined {
|
|
395
|
+
if (this.apps.has(segment)) return segment;
|
|
396
|
+
for (const app of this.apps.values()) {
|
|
397
|
+
if (app.path === segment || (app.name && app.name.endsWith('/' + segment))) return app.name ?? undefined;
|
|
398
|
+
}
|
|
399
|
+
return undefined;
|
|
400
|
+
}
|
|
401
|
+
|
|
368
402
|
/**
|
|
369
403
|
* Load and initialize an application.
|
|
370
|
-
*
|
|
371
|
-
* @param appId - Application identifier (must be already registered)
|
|
404
|
+
* @param appName - Application name (must be already registered)
|
|
372
405
|
* @param container - Optional DOM element to render into (if provided, auto-renders after loading)
|
|
373
|
-
* @returns Promise that resolves when app is initialized and rendered
|
|
374
406
|
*/
|
|
375
|
-
async loadApp(
|
|
376
|
-
const app = this.apps.get(
|
|
407
|
+
async loadApp(appName: string, container?: HTMLElement): Promise<void> {
|
|
408
|
+
const app = this.apps.get(appName);
|
|
377
409
|
if (!app) {
|
|
378
|
-
throw new Error(`App '${
|
|
410
|
+
throw new Error(`App '${appName}' not found. Make sure it's registered.`);
|
|
379
411
|
}
|
|
380
412
|
|
|
381
413
|
logger.info(`Loading app: ${app.name}...`);
|
|
@@ -442,25 +474,21 @@ class AppLoaderService {
|
|
|
442
474
|
|
|
443
475
|
this.currentApp = app;
|
|
444
476
|
logger.info(`App ${app.name} loaded successfully`);
|
|
445
|
-
|
|
446
|
-
// Update document metadata from app
|
|
477
|
+
this.preferredLayoutId = await this.getPreferredLayoutId();
|
|
447
478
|
this.updateDocumentMetadata(app);
|
|
448
|
-
|
|
449
|
-
// Auto-render if container provided
|
|
450
479
|
if (container) {
|
|
451
480
|
this.renderApp(container);
|
|
452
481
|
}
|
|
453
482
|
|
|
454
483
|
// Dispatch event for components to react to app changes
|
|
455
|
-
window.dispatchEvent(new CustomEvent('app-loaded', { detail: {
|
|
484
|
+
window.dispatchEvent(new CustomEvent('app-loaded', { detail: { appName: app.name } }));
|
|
456
485
|
}
|
|
457
486
|
|
|
458
487
|
/**
|
|
459
488
|
* Updates document title and favicon from app metadata
|
|
460
489
|
*/
|
|
461
490
|
private updateDocumentMetadata(app: AppDefinition): void {
|
|
462
|
-
|
|
463
|
-
document.title = app.name;
|
|
491
|
+
document.title = app.name ?? '';
|
|
464
492
|
|
|
465
493
|
// Set favicon if provided in metadata
|
|
466
494
|
if (app.metadata?.favicon) {
|
|
@@ -478,7 +506,8 @@ class AppLoaderService {
|
|
|
478
506
|
|
|
479
507
|
/**
|
|
480
508
|
* Render the current application to the DOM.
|
|
481
|
-
*
|
|
509
|
+
* Resolves the layout by layoutId (default 'standard'), renders its component, then calls layout.onShow if defined.
|
|
510
|
+
*
|
|
482
511
|
* @param container - DOM element to render into
|
|
483
512
|
*/
|
|
484
513
|
renderApp(container: HTMLElement): void {
|
|
@@ -486,23 +515,39 @@ class AppLoaderService {
|
|
|
486
515
|
throw new Error('No app loaded. Call loadApp() first.');
|
|
487
516
|
}
|
|
488
517
|
|
|
489
|
-
const
|
|
518
|
+
const layoutId = this.preferredLayoutId ?? this.currentApp.layoutId ?? 'standard';
|
|
519
|
+
const layouts = contributionRegistry.getContributions<LayoutContribution>(SYSTEM_LAYOUTS);
|
|
520
|
+
let layout = layouts.find((c) => c.id === layoutId);
|
|
521
|
+
if (!layout) {
|
|
522
|
+
logger.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
|
|
523
|
+
layout = layouts.find((c) => c.id === 'standard');
|
|
524
|
+
}
|
|
525
|
+
if (!layout) {
|
|
526
|
+
throw new Error(`No layout found for layoutId '${layoutId}' and no 'standard' layout registered.`);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const r = layout.component;
|
|
530
|
+
container.innerHTML = '';
|
|
490
531
|
if (typeof r === 'string') {
|
|
491
|
-
|
|
492
|
-
container.innerHTML = '';
|
|
493
|
-
container.appendChild(el);
|
|
532
|
+
container.appendChild(document.createElement(r));
|
|
494
533
|
} else if (r && typeof r === 'object' && 'tag' in r) {
|
|
495
534
|
const el = document.createElement(r.tag);
|
|
496
535
|
for (const [key, value] of Object.entries(r.attributes ?? {})) {
|
|
497
536
|
el.setAttribute(key, value);
|
|
498
537
|
}
|
|
499
|
-
container.innerHTML = '';
|
|
500
538
|
container.appendChild(el);
|
|
501
539
|
} else if (typeof r === 'function') {
|
|
502
|
-
|
|
503
|
-
render(template, container);
|
|
540
|
+
render(r(), container);
|
|
504
541
|
} else {
|
|
505
|
-
|
|
542
|
+
throw new Error(`Layout '${layout.id}' has invalid component.`);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (layout.onShow) {
|
|
546
|
+
requestAnimationFrame(() => {
|
|
547
|
+
void Promise.resolve(layout!.onShow!()).catch((err) =>
|
|
548
|
+
logger.error(`Layout onShow failed for '${layout!.id}': ${getErrorMessage(err)}`)
|
|
549
|
+
);
|
|
550
|
+
});
|
|
506
551
|
}
|
|
507
552
|
logger.info(`Rendered ${this.currentApp.name}`);
|
|
508
553
|
}
|
|
@@ -540,13 +585,48 @@ class AppLoaderService {
|
|
|
540
585
|
if (!this.apps.has(appId)) {
|
|
541
586
|
throw new Error(`App '${appId}' not found. Make sure it's registered.`);
|
|
542
587
|
}
|
|
543
|
-
|
|
544
588
|
try {
|
|
545
589
|
await appSettings.set(AppLoaderService.PREFERRED_APP_KEY, appId);
|
|
546
|
-
this.
|
|
590
|
+
this.defaultAppName = appId;
|
|
547
591
|
logger.info(`Set preferred app to: ${appId}`);
|
|
548
592
|
} catch (error) {
|
|
549
|
-
logger.error(`Failed to persist preferred app
|
|
593
|
+
logger.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
|
|
594
|
+
throw error;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
getRegisteredLayouts(): LayoutContribution[] {
|
|
599
|
+
return contributionRegistry.getContributions<LayoutContribution>(SYSTEM_LAYOUTS);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
getCurrentLayoutId(): string {
|
|
603
|
+
return this.preferredLayoutId ?? this.currentApp?.layoutId ?? 'standard';
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async getPreferredLayoutId(): Promise<string | undefined> {
|
|
607
|
+
try {
|
|
608
|
+
return await appSettings.get(AppLoaderService.PREFERRED_LAYOUT_KEY);
|
|
609
|
+
} catch (error) {
|
|
610
|
+
logger.debug(`Failed to get preferred layout ID: ${getErrorMessage(error)}`);
|
|
611
|
+
return undefined;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
async setPreferredLayoutId(layoutId: string): Promise<void> {
|
|
616
|
+
const layouts = this.getRegisteredLayouts();
|
|
617
|
+
if (!layouts.some((l) => l.id === layoutId)) {
|
|
618
|
+
throw new Error(`Layout '${layoutId}' not found.`);
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
await appSettings.set(AppLoaderService.PREFERRED_LAYOUT_KEY, layoutId);
|
|
622
|
+
this.preferredLayoutId = layoutId;
|
|
623
|
+
logger.info(`Set preferred layout to: ${layoutId}`);
|
|
624
|
+
if (this.currentApp && this.container) {
|
|
625
|
+
this.renderApp(this.container);
|
|
626
|
+
}
|
|
627
|
+
window.dispatchEvent(new CustomEvent('layout-changed', { detail: { layoutId } }));
|
|
628
|
+
} catch (error) {
|
|
629
|
+
logger.error(`Failed to persist preferred layout: ${getErrorMessage(error)}`);
|
|
550
630
|
throw error;
|
|
551
631
|
}
|
|
552
632
|
}
|
|
@@ -554,11 +634,11 @@ class AppLoaderService {
|
|
|
554
634
|
/**
|
|
555
635
|
* Select which app to load based on priority:
|
|
556
636
|
* 1. appId URL parameter (?appId=...)
|
|
557
|
-
* 2. App
|
|
558
|
-
* 3. App
|
|
637
|
+
* 2. App from current page URL path (/geospace)
|
|
638
|
+
* 3. App from app URL parameter (?app=...)
|
|
559
639
|
* 4. App registered by extension
|
|
560
|
-
* 5. Preferred app
|
|
561
|
-
* 6. Default app
|
|
640
|
+
* 5. Preferred app from settings
|
|
641
|
+
* 6. Default app
|
|
562
642
|
* 7. First registered app
|
|
563
643
|
*/
|
|
564
644
|
private async selectAppToLoad(options: {
|
|
@@ -568,59 +648,62 @@ class AppLoaderService {
|
|
|
568
648
|
appsBeforeExtension: number;
|
|
569
649
|
}): Promise<string | undefined> {
|
|
570
650
|
const { appIdFromUrl, appIdFromPath, appIdFromAppUrl, appsBeforeExtension } = options;
|
|
571
|
-
|
|
651
|
+
|
|
572
652
|
if (appIdFromUrl) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
653
|
+
const name = this.findAppNameBySegment(appIdFromUrl) ?? appIdFromUrl;
|
|
654
|
+
if (this.apps.has(name)) {
|
|
655
|
+
logger.info(`Loading app specified by URL parameter 'appId': ${name}`);
|
|
656
|
+
return name;
|
|
576
657
|
}
|
|
577
|
-
logger.warn(`App
|
|
658
|
+
logger.warn(`App '${appIdFromUrl}' from URL parameter not found`);
|
|
578
659
|
}
|
|
579
|
-
|
|
660
|
+
|
|
580
661
|
if (appIdFromPath) {
|
|
581
|
-
|
|
662
|
+
const name = this.findAppNameBySegment(appIdFromPath);
|
|
663
|
+
if (name) {
|
|
582
664
|
logger.info(`Loading app from URL path: ${appIdFromPath}`);
|
|
583
|
-
return
|
|
665
|
+
return name;
|
|
584
666
|
}
|
|
585
|
-
logger.debug(`App
|
|
667
|
+
logger.debug(`App for path '${appIdFromPath}' not found, continuing search`);
|
|
586
668
|
}
|
|
587
|
-
|
|
669
|
+
|
|
588
670
|
if (appIdFromAppUrl) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
671
|
+
const name = this.findAppNameBySegment(appIdFromAppUrl) ?? appIdFromAppUrl;
|
|
672
|
+
if (this.apps.has(name)) {
|
|
673
|
+
logger.info(`Loading app using segment from app URL path: ${name}`);
|
|
674
|
+
return name;
|
|
592
675
|
}
|
|
593
676
|
}
|
|
594
|
-
|
|
677
|
+
|
|
595
678
|
if (this.apps.size > appsBeforeExtension) {
|
|
596
679
|
const newlyRegisteredApps = Array.from(this.apps.values()).slice(appsBeforeExtension);
|
|
597
680
|
if (newlyRegisteredApps.length > 0) {
|
|
598
681
|
const app = newlyRegisteredApps[0];
|
|
599
|
-
logger.info(`Loading app registered by extension: ${app.name}
|
|
600
|
-
return app.
|
|
682
|
+
logger.info(`Loading app registered by extension: ${app.name}`);
|
|
683
|
+
return app.name;
|
|
601
684
|
}
|
|
602
685
|
}
|
|
603
|
-
|
|
604
|
-
const
|
|
605
|
-
if (
|
|
606
|
-
logger.info(`Loading preferred app from settings: ${
|
|
607
|
-
return
|
|
686
|
+
|
|
687
|
+
const preferred = await this.getPreferredAppId();
|
|
688
|
+
if (preferred && this.apps.has(preferred)) {
|
|
689
|
+
logger.info(`Loading preferred app from settings: ${preferred}`);
|
|
690
|
+
return preferred;
|
|
608
691
|
}
|
|
609
|
-
|
|
610
|
-
if (this.
|
|
611
|
-
|
|
612
|
-
return this.defaultAppId;
|
|
613
|
-
}
|
|
614
|
-
logger.warn(`Default app '${this.defaultAppId}' not found`);
|
|
692
|
+
|
|
693
|
+
if (this.defaultAppName && this.apps.has(this.defaultAppName)) {
|
|
694
|
+
return this.defaultAppName;
|
|
615
695
|
}
|
|
616
|
-
|
|
696
|
+
if (this.defaultAppName) {
|
|
697
|
+
logger.warn(`Default app '${this.defaultAppName}' not found`);
|
|
698
|
+
}
|
|
699
|
+
|
|
617
700
|
const registeredApps = this.getRegisteredApps();
|
|
618
701
|
if (registeredApps.length > 0) {
|
|
619
702
|
const app = registeredApps[0];
|
|
620
|
-
logger.info(`Loading first registered app: ${app.name}
|
|
621
|
-
return app.
|
|
703
|
+
logger.info(`Loading first registered app: ${app.name}`);
|
|
704
|
+
return app.name;
|
|
622
705
|
}
|
|
623
|
-
|
|
706
|
+
|
|
624
707
|
return undefined;
|
|
625
708
|
}
|
|
626
709
|
}
|
package/src/core/constants.ts
CHANGED
|
@@ -7,6 +7,7 @@ export const TOOLBAR_BOTTOM_CENTER = "app-toolbars-bottom-center"
|
|
|
7
7
|
export const TOOLBAR_BOTTOM_END = "app-toolbars-bottom-end"
|
|
8
8
|
|
|
9
9
|
export const SYSTEM_VIEWS = "system-views"
|
|
10
|
+
export const SYSTEM_LAYOUTS = "system.layouts"
|
|
10
11
|
|
|
11
12
|
// VS Code-style layout containers
|
|
12
13
|
export const EDITOR_AREA_MAIN = "editor-area-main"
|
|
@@ -25,7 +25,7 @@ export interface CommandContribution extends Contribution {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export interface HTMLContribution extends Contribution {
|
|
28
|
-
|
|
28
|
+
component: string | (() => TemplateResult)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface TabContribution extends Contribution {
|
|
@@ -40,20 +40,18 @@ export interface TabContribution extends Contribution {
|
|
|
40
40
|
component?: (id: string) => TemplateResult;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export interface PaneContribution extends Contribution {
|
|
44
|
-
name: string;
|
|
45
|
-
size?: number;
|
|
46
|
-
minSize?: number;
|
|
47
|
-
maxSize?: number;
|
|
48
|
-
order?: number;
|
|
49
|
-
component: () => TemplateResult;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
43
|
export interface IconContribution extends Contribution {
|
|
53
44
|
mappings: Record<string, string>;
|
|
54
45
|
priority?: number;
|
|
55
46
|
}
|
|
56
47
|
|
|
48
|
+
export interface LayoutContribution extends Contribution {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
component: string | { tag: string; attributes?: Record<string, string> } | (() => TemplateResult);
|
|
52
|
+
onShow?: () => void | Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
|
|
57
55
|
class ContributionRegistry {
|
|
58
56
|
private contributions: Map<string, Contribution[]> = new Map();
|
|
59
57
|
|
|
@@ -16,7 +16,7 @@ export interface EditorInput {
|
|
|
16
16
|
icon?: string;
|
|
17
17
|
data: any;
|
|
18
18
|
noOverflow?: boolean;
|
|
19
|
-
|
|
19
|
+
component: (container: any, tab: HTMLElement) => any;
|
|
20
20
|
state: { [key: string]: any };
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -246,11 +246,11 @@ class EditorRegistry {
|
|
|
246
246
|
return
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
if (!("
|
|
249
|
+
if (!("component" in editorInput)) {
|
|
250
250
|
editorInput = await this.handleInput(editorInput, preferredEditorId)
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
if (!editorInput || !("
|
|
253
|
+
if (!editorInput || !("component" in editorInput)) {
|
|
254
254
|
return
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -264,7 +264,7 @@ class EditorRegistry {
|
|
|
264
264
|
icon: editorInput.icon,
|
|
265
265
|
closable: true,
|
|
266
266
|
noOverflow: editorInput.noOverflow,
|
|
267
|
-
component: editorInput.
|
|
267
|
+
component: editorInput.component
|
|
268
268
|
} as TabContribution)
|
|
269
269
|
}
|
|
270
270
|
|
package/src/core/index.ts
CHANGED
package/src/parts/contextmenu.ts
CHANGED
|
@@ -198,8 +198,8 @@ export class LyraContextMenu extends LyraElement {
|
|
|
198
198
|
${commandContribution.label}
|
|
199
199
|
</lyra-command>
|
|
200
200
|
`;
|
|
201
|
-
} else if ("
|
|
202
|
-
const contents = (contribution as HTMLContribution).
|
|
201
|
+
} else if ("component" in contribution) {
|
|
202
|
+
const contents = (contribution as HTMLContribution).component;
|
|
203
203
|
if (contents instanceof Function) {
|
|
204
204
|
return contents();
|
|
205
205
|
}
|
package/src/parts/toolbar.ts
CHANGED
|
@@ -186,7 +186,7 @@ export class LyraToolbar extends LyraElement {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
private isToolbarItem(contribution: Contribution): boolean {
|
|
189
|
-
return "command" in contribution || "
|
|
189
|
+
return "command" in contribution || "component" in contribution;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
contributionCreator(contribution: Contribution) {
|
|
@@ -203,8 +203,8 @@ export class LyraToolbar extends LyraElement {
|
|
|
203
203
|
</wa-button>
|
|
204
204
|
`;
|
|
205
205
|
}
|
|
206
|
-
if ("
|
|
207
|
-
const contents = (contribution as HTMLContribution).
|
|
206
|
+
if ("component" in contribution) {
|
|
207
|
+
const contents = (contribution as HTMLContribution).component
|
|
208
208
|
if (contents instanceof Function) {
|
|
209
209
|
return contents()
|
|
210
210
|
}
|
package/src/vite-env.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/// <reference types="vite/client" />
|
|
2
2
|
|
|
3
|
+
/** Injected by resolveDepVersionsPlugin when hostConfig is true. */
|
|
4
|
+
declare const __RESOLVED_PACKAGE_INFO__: {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
dependencies: Record<string, string>;
|
|
9
|
+
marketplaceCatalogUrls?: string[];
|
|
10
|
+
} | undefined;
|
|
11
|
+
|
|
3
12
|
declare module 'toastify-js' {
|
|
4
13
|
interface ToastifyOptions {
|
|
5
14
|
text?: string;
|