@equinor/fusion-framework-module-app 1.0.11 → 1.1.0

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/package.json CHANGED
@@ -1,33 +1,37 @@
1
1
  {
2
- "name": "@equinor/fusion-framework-module-app",
3
- "version": "1.0.11",
4
- "description": "",
5
- "main": "dist/esm/index.js",
6
- "exports": {
7
- ".": "./dist/esm/index.js"
8
- },
9
- "types": "dist/types/index.d.ts",
10
- "scripts": {
11
- "build": "npm run build:typescript",
12
- "build:typescript": "tsc -b --verbose"
13
- },
14
- "keywords": [],
15
- "author": "",
16
- "license": "ISC",
17
- "publishConfig": {
18
- "access": "public"
19
- },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/equinor/fusion-framework.git",
23
- "directory": "packages/module-apps"
24
- },
25
- "dependencies": {
26
- "@equinor/fusion-framework-module": "^1.2.5",
27
- "rxjs": "^7.5.6"
28
- },
29
- "devDependencies": {
30
- "typescript": "^4.8.4"
31
- },
32
- "gitHead": "4476578317fe48e58849be381144cdfa193c3248"
2
+ "name": "@equinor/fusion-framework-module-app",
3
+ "version": "1.1.0",
4
+ "description": "",
5
+ "main": "dist/esm/index.js",
6
+ "exports": {
7
+ ".": "./dist/esm/index.js"
8
+ },
9
+ "types": "dist/types/index.d.ts",
10
+ "scripts": {
11
+ "build": "npm run build:typescript",
12
+ "build:typescript": "tsc -b --verbose"
13
+ },
14
+ "keywords": [],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/equinor/fusion-framework.git",
23
+ "directory": "packages/module-app"
24
+ },
25
+ "dependencies": {
26
+ "@equinor/fusion-observable": "^1.3.0",
27
+ "rxjs": "^7.5.7"
28
+ },
29
+ "devDependencies": {
30
+ "@equinor/fusion-framework-module": "^1.2.6",
31
+ "typescript": "^4.8.4"
32
+ },
33
+ "peerDependencies": {
34
+ "@equinor/fusion-observable": "^1.2.1"
35
+ },
36
+ "gitHead": "21ae1ec0a760c03a0887eced5532de8443274916"
33
37
  }
@@ -0,0 +1,75 @@
1
+ import { AnyModule, ModuleInitializerArgs } from '@equinor/fusion-framework-module';
2
+ import { IHttpClient } from '@equinor/fusion-framework-module-http';
3
+ import { QueryCtorOptions } from '@equinor/fusion-observable/query';
4
+ import { moduleKey } from './module';
5
+ import type { AppConfig, AppManifest, ModuleDeps } from './types';
6
+
7
+ export interface IAppModuleConfig {
8
+ getApp: QueryCtorOptions<AppManifest, { appKey: string }>;
9
+ // TODO: add filter
10
+ getApps: QueryCtorOptions<AppManifest[], void>;
11
+ getConfig: QueryCtorOptions<AppConfig, { appKey: string; tag?: string }>;
12
+ }
13
+
14
+ export interface IAppConfigurator<TDeps extends Array<AnyModule>> {
15
+ createConfig: (
16
+ args: ModuleInitializerArgs<IAppConfigurator<TDeps>, TDeps>
17
+ ) => Promise<IAppModuleConfig>;
18
+ processConfig: (config: IAppModuleConfig) => IAppModuleConfig;
19
+ }
20
+
21
+ export class AppConfigurator<TDeps extends ModuleDeps = ModuleDeps>
22
+ implements IAppConfigurator<TDeps>
23
+ {
24
+ defaultExpireTime = 1 * 60 * 1000;
25
+
26
+ /**
27
+ * WARNING: this function will be remove in future
28
+ */
29
+ protected async _createHttpClient(
30
+ init: ModuleInitializerArgs<IAppConfigurator<TDeps>, TDeps>
31
+ ): Promise<IHttpClient> {
32
+ const http = await init.requireInstance('http');
33
+ /** check if the http provider has configure a client */
34
+ if (http.hasClient(moduleKey)) {
35
+ return http.createClient(moduleKey);
36
+ } else {
37
+ /** load service discovery module */
38
+ const serviceDiscovery = await init.requireInstance('serviceDiscovery');
39
+ /** resolve and create a client from discovery */
40
+ return await serviceDiscovery.createClient('portal');
41
+ }
42
+ }
43
+
44
+ public async createConfig(
45
+ args: ModuleInitializerArgs<IAppConfigurator<TDeps>, TDeps>
46
+ ): Promise<IAppModuleConfig> {
47
+ const httpClient = await this._createHttpClient(args);
48
+ const config: IAppModuleConfig = {
49
+ getApp: {
50
+ client: {
51
+ fn: ({ appKey }) => httpClient.json$(`/api/apps/${appKey}`),
52
+ },
53
+ key: ({ appKey }) => appKey,
54
+ },
55
+ getApps: {
56
+ client: {
57
+ fn: () => httpClient.json$(`/api/apps`),
58
+ },
59
+ key: () => 'apps',
60
+ },
61
+ getConfig: {
62
+ client: {
63
+ fn: ({ appKey, tag }) =>
64
+ httpClient.json$(`/api/apps/${appKey}/config${tag ? `?tag=${tag}` : ''}`),
65
+ },
66
+ key: (args) => JSON.stringify(args),
67
+ },
68
+ };
69
+ return this.processConfig(config);
70
+ }
71
+
72
+ public processConfig(config: IAppModuleConfig): IAppModuleConfig {
73
+ return config;
74
+ }
75
+ }
package/src/helpers.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { AppManifest } from './types';
2
+
3
+ export const compareAppManifest = <T extends AppManifest>(a?: T, b?: T): boolean =>
4
+ JSON.stringify(a) === JSON.stringify(b);
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export { AppConfigurator, IAppConfigurator, IAppModuleConfig } from './configurator';
2
+ export { AppProvider, IAppProvider } from './provider';
3
+
4
+ export * from './types';
5
+
6
+ export { default, AppModule, module, moduleKey } from './module';
package/src/module.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { Module } from '@equinor/fusion-framework-module';
2
+ import { ModuleDeps } from './types';
3
+
4
+ import { IAppConfigurator, AppConfigurator } from './configurator';
5
+ import { AppProvider, IAppProvider } from './provider';
6
+
7
+ export const moduleKey = 'app';
8
+
9
+ export type AppModule = Module<
10
+ typeof moduleKey,
11
+ IAppProvider,
12
+ IAppConfigurator<ModuleDeps>,
13
+ ModuleDeps
14
+ >;
15
+
16
+ export const module: AppModule = {
17
+ name: moduleKey,
18
+ configure: () => new AppConfigurator(),
19
+ initialize: async (args) => {
20
+ const config = await args.config.createConfig(args);
21
+ const event = await args.requireInstance('event').catch(() => undefined);
22
+ return new AppProvider({ config, event });
23
+ },
24
+ dispose: (args) => {
25
+ (args.instance as unknown as AppProvider).dispose();
26
+ },
27
+ };
28
+
29
+ export default module;
30
+
31
+ declare module '@equinor/fusion-framework-module' {
32
+ interface Modules {
33
+ app: AppModule;
34
+ }
35
+ }
@@ -0,0 +1,121 @@
1
+ import {
2
+ BehaviorSubject,
3
+ distinctUntilChanged,
4
+ Observable,
5
+ pairwise,
6
+ Subscription,
7
+ takeWhile,
8
+ } from 'rxjs';
9
+
10
+ import { ModuleType } from '@equinor/fusion-framework-module';
11
+
12
+ import { Query, queryValue } from '@equinor/fusion-observable/query';
13
+
14
+ import {
15
+ EventModule,
16
+ FrameworkEvent,
17
+ FrameworkEventInit,
18
+ } from '@equinor/fusion-framework-module-event';
19
+
20
+ import { IAppModuleConfig } from './configurator';
21
+ import { compareAppManifest } from './helpers';
22
+
23
+ import type { AppConfig, AppManifest } from './types';
24
+
25
+ export interface IAppProvider {
26
+ getApp(appKey: string): Observable<AppManifest>;
27
+ getAllApps(): Observable<AppManifest[]>;
28
+ getAppConfig<TType = unknown>(appKey: string): Observable<AppConfig<TType>>;
29
+ setCurrentApp(appKey: string): void;
30
+ readonly current$: Observable<AppManifest | undefined>;
31
+ }
32
+
33
+ export class AppProvider extends Observable<AppManifest | undefined> implements IAppProvider {
34
+ #appClient: Query<AppManifest, { appKey: string }>;
35
+ #appsClient: Query<AppManifest[], void>;
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ #configClient: Query<AppConfig<any>, { appKey: string; tag?: string }>;
38
+
39
+ #current$: BehaviorSubject<AppManifest | undefined>;
40
+
41
+ #subscription = new Subscription();
42
+
43
+ get current(): AppManifest | undefined {
44
+ return this.#current$.value;
45
+ }
46
+
47
+ get current$(): Observable<AppManifest | undefined> {
48
+ return this.#current$.pipe(distinctUntilChanged(compareAppManifest));
49
+ }
50
+
51
+ constructor(args: { config: IAppModuleConfig; event?: ModuleType<EventModule> }) {
52
+ super((observer) => this.current$.subscribe(observer));
53
+
54
+ const { event, config } = args;
55
+
56
+ this.#current$ = new BehaviorSubject<AppManifest | undefined>(undefined);
57
+
58
+ this.#appClient = new Query(config.getApp);
59
+ this.#appsClient = new Query(config.getApps);
60
+ this.#configClient = new Query(config.getConfig);
61
+
62
+ this.#subscription.add(this.#appClient.complete);
63
+ this.#subscription.add(this.#appsClient.complete);
64
+ this.#subscription.add(this.#configClient.complete);
65
+ this.#subscription.add(
66
+ this.current$
67
+ .pipe(
68
+ pairwise(),
69
+ takeWhile(() => !!event)
70
+ )
71
+ .subscribe(([previous, next]) => {
72
+ event?.dispatchEvent('onCurrentAppChanged', {
73
+ source: this,
74
+ detail: { previous, next },
75
+ });
76
+ })
77
+ );
78
+ }
79
+
80
+ public getApp(appKey: string): Observable<AppManifest> {
81
+ return queryValue(this.#appClient.query({ appKey }));
82
+ }
83
+
84
+ public getAllApps(): Observable<AppManifest[]> {
85
+ return queryValue(this.#appsClient.query());
86
+ }
87
+
88
+ public getAppConfig<TType = unknown>(
89
+ appKey: string,
90
+ tag?: string
91
+ ): Observable<AppConfig<TType>> {
92
+ return queryValue(this.#configClient.query({ appKey, tag }));
93
+ }
94
+
95
+ public setCurrentApp(appKey: string): Promise<void> {
96
+ return new Promise((complete, error) => {
97
+ const query$ = this.#appClient.query({ appKey }, { skipQueue: true });
98
+ this.#subscription.add(
99
+ queryValue(query$).subscribe({
100
+ next: (x) => this.#current$.next(x),
101
+ error,
102
+ complete,
103
+ })
104
+ );
105
+ });
106
+ }
107
+
108
+ public dispose() {
109
+ this.#subscription.unsubscribe();
110
+ }
111
+ }
112
+
113
+ declare module '@equinor/fusion-framework-module-event' {
114
+ interface FrameworkEventMap {
115
+ onCurrentAppChanged: FrameworkEvent<
116
+ FrameworkEventInit<{ next?: AppManifest; previous?: AppManifest }, IAppProvider>
117
+ >;
118
+ }
119
+ }
120
+
121
+ export default AppProvider;
package/src/types.ts CHANGED
@@ -1,47 +1,9 @@
1
- export enum ContextTypes {
2
- Contract = 'Contract',
3
- OrgChart = 'OrgChart',
4
- PDP = 'PDP',
5
- PimsDomain = 'PimsDomain',
6
- Portfolio = 'Portfolio',
7
- Project = 'Project',
8
- ProjectMaster = 'ProjectMaster',
9
- Facility = 'Facility',
10
- TpdPortfolio = 'TpdPortfolio',
11
- }
1
+ import type { EventModule } from '@equinor/fusion-framework-module-event';
2
+ import type { HttpModule } from '@equinor/fusion-framework-module-http';
3
+ import type { ServiceDiscoveryModule } from '@equinor/fusion-framework-module-service-discovery';
12
4
 
13
- export class ContextType {
14
- constructor(
15
- readonly id: ContextTypes,
16
- readonly isChildType: boolean,
17
- readonly parentTypeIds: string[] = []
18
- ) {}
19
- }
20
-
21
- type ParentContext = {
22
- id: string;
23
- type: ContextType;
24
- };
25
-
26
- export type Context = {
27
- id: string;
28
- externalId: string | null;
29
- type: ContextType;
30
- title: string;
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- value: any;
33
- isActive: boolean;
34
- parent: ParentContext;
35
- };
36
-
37
- export type ContextManifest = {
38
- readonly types: ContextTypes[];
39
- readonly placeholder?: string;
40
- readonly nullable?: boolean;
41
- filterContexts?: (contexts: Context[]) => Context[];
42
- buildUrl?: (context: Context | null, url: string) => string;
43
- getContextFromUrl?: (url: string) => string;
44
- };
5
+ // TODO: change to module-services when new app service is created
6
+ export type ModuleDeps = [HttpModule, ServiceDiscoveryModule, EventModule];
45
7
 
46
8
  export type AppType = 'standalone' | 'report' | 'launcher';
47
9
 
@@ -65,7 +27,7 @@ export type AppManifest = {
65
27
  description: string;
66
28
  type: AppType;
67
29
  tags: string[];
68
- context?: ContextManifest;
30
+ // context?: ContextManifest;
69
31
  auth?: AppAuth[];
70
32
  icon?: string;
71
33
  order: number | null;
@@ -75,3 +37,10 @@ export type AppManifest = {
75
37
  category: AppCategory | null;
76
38
  hide?: boolean;
77
39
  };
40
+
41
+ export type Endpoint = { name: string; uri: string; scopes?: string[] };
42
+
43
+ export type AppConfig<TEnvironment = unknown> = {
44
+ environment: TEnvironment;
45
+ endpoints: Record<string, string | Endpoint>;
46
+ };
package/tsconfig.json CHANGED
@@ -9,6 +9,12 @@
9
9
  "references": [
10
10
  {
11
11
  "path": "../module"
12
+ },
13
+ {
14
+ "path": "../observable"
15
+ },
16
+ {
17
+ "path": "../module-http"
12
18
  }
13
19
  ],
14
20
  "include": [
package/yarn-error.log ADDED
@@ -0,0 +1,66 @@
1
+ Arguments:
2
+ /Users/odin.rochmann/.nvm/versions/node/v16.14.0/bin/node /Users/odin.rochmann/.yarn/bin/yarn.js
3
+
4
+ PATH:
5
+ /Users/odin.rochmann/.yarn/bin:/Users/odin.rochmann/.config/yarn/global/node_modules/.bin:/Users/odin.rochmann/.nvm/versions/node/v16.14.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/MacGPG2/bin:/usr/local/share/dotnet:~/.dotnet/tools:/Users/odin.rochmann/.yarn/bin:/Users/odin.rochmann/.config/yarn/global/node_modules/.bin:/Users/odin.rochmann/.nvm/versions/node/v16.14.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/odin.rochmann/.dotnet/tools:/Users/odin.rochmann/.dotnet/tools
6
+
7
+ Yarn version:
8
+ 1.22.19
9
+
10
+ Node version:
11
+ 16.14.0
12
+
13
+ Platform:
14
+ darwin arm64
15
+
16
+ Trace:
17
+ SyntaxError: /Users/odin.rochmann/dev/fusion/fusion-framework/packages/module-app/package.json: Unexpected token } in JSON at position 979
18
+ at JSON.parse (<anonymous>)
19
+ at /Users/odin.rochmann/.yarn/lib/cli.js:1629:59
20
+ at Generator.next (<anonymous>)
21
+ at step (/Users/odin.rochmann/.yarn/lib/cli.js:310:30)
22
+ at /Users/odin.rochmann/.yarn/lib/cli.js:321:13
23
+
24
+ npm manifest:
25
+ {
26
+ "name": "@equinor/fusion-framework-module-app",
27
+ "version": "1.0.12",
28
+ "description": "",
29
+ "main": "dist/esm/index.js",
30
+ "exports": {
31
+ ".": "./dist/esm/index.js"
32
+ },
33
+ "types": "dist/types/index.d.ts",
34
+ "scripts": {
35
+ "build": "npm run build:typescript",
36
+ "build:typescript": "tsc -b --verbose"
37
+ },
38
+ "keywords": [],
39
+ "author": "",
40
+ "license": "ISC",
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/equinor/fusion-framework.git",
47
+ "directory": "packages/module-app"
48
+ },
49
+ "devDependencies": {
50
+ "@equinor/fusion-observable": "^1.2.1",
51
+ "@equinor/fusion-framework-module": "^1.2.6",
52
+ "rxjs": "^7.5.7",
53
+ "typescript": "^4.8.4"
54
+ },
55
+ "peerDependencies": {
56
+ "@equinor/fusion-observable": "^1.2.1",
57
+ "@equinor/fusion-framework-module": "^1.2.6",
58
+ "rxjs": "^7.5.7"
59
+ },
60
+ }
61
+
62
+ yarn manifest:
63
+ No manifest
64
+
65
+ Lockfile:
66
+ No lockfile
package/TODO.md DELETED
@@ -1,5 +0,0 @@
1
- [ ] develope configurator
2
- [ ] develope provider
3
- [ ] develope module
4
-
5
- > awaiting new app frame-work
@@ -1,2 +0,0 @@
1
- "use strict";
2
- //# sourceMappingURL=app-configurator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-configurator.js","sourceRoot":"","sources":["../../src/app-configurator.ts"],"names":[],"mappings":""}
@@ -1,25 +0,0 @@
1
- import { BehaviorSubject } from 'rxjs';
2
- export class AppProvider {
3
- constructor() {
4
- this._app$ = new BehaviorSubject({});
5
- this._currentApp$ = new BehaviorSubject(null);
6
- }
7
- get app$() {
8
- return this._app$.asObservable();
9
- }
10
- get currentApp() {
11
- return this._currentApp$.value;
12
- }
13
- setCurrentApp(app) {
14
- if (typeof app === 'string') {
15
- const next = this._app$.value[app];
16
- if (!next) {
17
- console.warn('could not find any app for key', app);
18
- }
19
- this._currentApp$.next(next);
20
- }
21
- this._currentApp$.next(app);
22
- }
23
- }
24
- export default AppProvider;
25
- //# sourceMappingURL=app-provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-provider.js","sourceRoot":"","sources":["../../src/app-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAc,MAAM,MAAM,CAAC;AAGnD,MAAM,OAAO,WAAW;IAYpB;QACI,IAAI,CAAC,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,eAAe,CAAqB,IAAI,CAAC,CAAC;IACtE,CAAC;IAXD,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;IACrC,CAAC;IAED,IAAI,UAAU;QACV,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IACnC,CAAC;IAOD,aAAa,CAAC,GAAyB;QACnC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEnC,IAAI,CAAC,IAAI,EAAE;gBACP,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;aACvD;YACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAChC;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAkB,CAAC,CAAC;IAC/C,CAAC;CACJ;AAED,eAAe,WAAW,CAAC"}
File without changes
@@ -1,11 +0,0 @@
1
- import { BehaviorSubject, Observable } from 'rxjs';
2
- import { AppManifest } from './types';
3
- export declare class AppProvider {
4
- protected _app$: BehaviorSubject<Record<string, AppManifest>>;
5
- protected _currentApp$: BehaviorSubject<AppManifest | null>;
6
- get app$(): Observable<Record<string, AppManifest>>;
7
- get currentApp(): AppManifest | null;
8
- constructor();
9
- setCurrentApp(app: string | AppManifest): void;
10
- }
11
- export default AppProvider;
File without changes
@@ -1,34 +0,0 @@
1
- import { BehaviorSubject, Observable } from 'rxjs';
2
- import { AppManifest } from './types';
3
-
4
- export class AppProvider {
5
- protected _app$: BehaviorSubject<Record<string, AppManifest>>;
6
- protected _currentApp$: BehaviorSubject<AppManifest | null>;
7
-
8
- get app$(): Observable<Record<string, AppManifest>> {
9
- return this._app$.asObservable();
10
- }
11
-
12
- get currentApp(): AppManifest | null {
13
- return this._currentApp$.value;
14
- }
15
-
16
- constructor() {
17
- this._app$ = new BehaviorSubject({});
18
- this._currentApp$ = new BehaviorSubject<AppManifest | null>(null);
19
- }
20
-
21
- setCurrentApp(app: string | AppManifest): void {
22
- if (typeof app === 'string') {
23
- const next = this._app$.value[app];
24
- // TODO - better handling
25
- if (!next) {
26
- console.warn('could not find any app for key', app);
27
- }
28
- this._currentApp$.next(next);
29
- }
30
- this._currentApp$.next(app as AppManifest);
31
- }
32
- }
33
-
34
- export default AppProvider;