forked from PAIR-code/lit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lit_app.ts
173 lines (154 loc) · 6.66 KB
/
lit_app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Import Services
// Import and add injection functionality to LitModule
import {reaction} from 'mobx';
import {Constructor, LitComponentLayouts} from '../lib/types';
import {ApiService} from '../services/api_service';
import {ClassificationService} from '../services/classification_service';
import {ColorService} from '../services/color_service';
import {FocusService} from '../services/focus_service';
import {GroupService} from '../services/group_service';
import {LitService} from '../services/lit_service';
import {ModulesService} from '../services/modules_service';
import {RegressionService} from '../services/regression_service';
import {SelectionService} from '../services/selection_service';
import {SettingsService} from '../services/settings_service';
import {SliceService} from '../services/slice_service';
import {AppState} from '../services/state_service';
import {StatusService} from '../services/status_service';
import {UrlService} from '../services/url_service';
/**
* The class responsible for building and managing the LIT App.
*/
export class LITApp {
constructor() {
this.buildServices();
}
/**
* Begins loading data from the LIT server, and computes the layout that
* the `modules` component will use to render.
*/
async initialize(layouts: LitComponentLayouts) {
const appState = this.getService(AppState);
const modulesService = this.getService(ModulesService);
appState.layouts = layouts;
await appState.initialize();
if (appState.metadata.pageTitle) {
document.querySelector('html head title')!.textContent = appState.metadata.pageTitle;
}
modulesService.initializeLayout(
appState.layout, appState.currentModelSpecs,
appState.currentDatasetSpec, appState.compareExamplesEnabled);
// If we need more than one selectionService, create and append it to the
// list.
const numSelectionServices = modulesService.numberOfSelectionServices;
const selectionServices = this.getServiceArray(SelectionService);
for (let i = 0; i < numSelectionServices - 1; i++) {
const selectionService = new SelectionService();
selectionService.setAppState(appState);
selectionServices.push(selectionService);
}
// Select the initial datapoint, if one was set in the url.
await this.getService(UrlService).syncSelectedDatapointToUrl(appState, selectionServices[0]);
// Reaction to sync other selection services to selections of the main one.
reaction(() => appState.compareExamplesEnabled, compareExamplesEnabled => {
this.syncSelectionServices();
}, {fireImmediately: true});
}
private readonly services =
new Map<Constructor<LitService>, LitService|LitService[]>();
/** Sync selection services */
syncSelectionServices() {
const selectionServices = this.getServiceArray(SelectionService);
selectionServices.slice(1).forEach((selectionService: SelectionService) => {
// TODO(lit-dev): can we just copy the object instead, and skip this
// logic?
selectionService.syncFrom(selectionServices[0]);
});
}
/** Simple DI service system */
getService<T extends LitService>(t: Constructor<T>): T {
let service = this.services.get(t);
/**
* Modules that don't support example comparison will always get index
* 0 of selectionService. This way we do not have to edit any module that
* does not explicitly support cloning
*/
if (Array.isArray(service)) {
service = service[0];
}
if (service === undefined) {
throw new Error(`Service is undefined: ${t.name}`);
}
return service as T;
}
/**
* Intended for selectionService only, returns an array of services for
* indexing within modules.
*/
getServiceArray<T extends LitService>(t: Constructor<T>): T[] {
const services = this.services.get(t) as T[];
if (services === undefined) {
throw new Error(`Service is undefined: ${t.name}`);
}
return services;
}
/**
* Builds services via simple constructor / composition based dependency
* injection. We'll might want to come up with something more robust down the
* line, but for now this allows us to construct all of our singleton
* services in one location in a simple way.
*/
private buildServices() {
const statusService = new StatusService();
const apiService = new ApiService(statusService);
const modulesService = new ModulesService();
const selectionService = new SelectionService();
const urlService = new UrlService();
const appState = new AppState(apiService, statusService);
const sliceService = new SliceService(selectionService, appState);
const classificationService =
new ClassificationService(apiService, appState);
const regressionService = new RegressionService(apiService, appState);
const settingsService =
new SettingsService(appState, modulesService, selectionService);
const groupService = new GroupService(appState);
const colorService = new ColorService(
appState, groupService, classificationService, regressionService);
const focusService = new FocusService(selectionService);
selectionService.setAppState(appState);
// Initialize url syncing of state
urlService.syncStateToUrl(appState, selectionService, modulesService);
// Populate the internal services map for dependency injection
this.services.set(ApiService, apiService);
this.services.set(AppState, appState);
this.services.set(ClassificationService, classificationService);
this.services.set(ColorService, colorService);
this.services.set(FocusService, focusService);
this.services.set(GroupService, groupService);
this.services.set(ModulesService, modulesService);
this.services.set(RegressionService, regressionService);
this.services.set(SelectionService, [selectionService]);
this.services.set(SettingsService, settingsService);
this.services.set(SliceService, sliceService);
this.services.set(StatusService, statusService);
this.services.set(UrlService, urlService);
}
}
/** The exported singleton instance of the LIT App */
export const app = new LITApp();