@matdata/yasgui 4.6.1

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/src/index.ts ADDED
@@ -0,0 +1,373 @@
1
+ import { EventEmitter } from "events";
2
+ import { merge, find, isEqual } from "lodash-es";
3
+ import initializeDefaults from "./defaults";
4
+ import PersistentConfig from "./PersistentConfig";
5
+ import { default as Tab, PersistedJson as PersistedTabJson } from "./Tab";
6
+
7
+ import { EndpointSelectConfig, CatalogueItem } from "./endpointSelect";
8
+ import * as shareLink from "./linkUtils";
9
+ import TabElements from "./TabElements";
10
+ import { default as Yasqe, PartialConfig as YasqeConfig, RequestConfig } from "@matdata/yasqe";
11
+ import { default as Yasr, Config as YasrConfig } from "@matdata/yasr";
12
+ import { addClass, removeClass } from "@matdata/yasgui-utils";
13
+ import GeoPlugin from "yasgui-geo-tg";
14
+ import GraphPlugin from "@matdata/yasgui-graph-plugin";
15
+ require("./index.scss");
16
+ require("@matdata/yasr/src/scss/global.scss");
17
+
18
+ // Register plugins to Yasr
19
+ Yasr.registerPlugin("Geo", GeoPlugin);
20
+ Yasr.registerPlugin("Graph", GraphPlugin);
21
+ if (window) {
22
+ //We're storing yasqe and yasr as a member of Yasgui, but _also_ in the window
23
+ //That way, we dont have to tweak e.g. pro plugins to register themselves to both
24
+ //Yasgui.Yasr _and_ Yasr.
25
+ if (Yasqe) (window as any).Yasqe = Yasqe;
26
+ if (Yasr) (window as any).Yasr = Yasr;
27
+ }
28
+ export type YasguiRequestConfig = Omit<RequestConfig<Yasgui>, "adjustQueryBeforeRequest"> & {
29
+ adjustQueryBeforeRequest: RequestConfig<Yasqe>["adjustQueryBeforeRequest"];
30
+ };
31
+ export interface Config<EndpointObject extends CatalogueItem = CatalogueItem> {
32
+ /**
33
+ * Autofocus yasqe on load or tab switch
34
+ */
35
+ autofocus: boolean;
36
+ endpointInfo: ((tab?: Tab) => Element) | undefined;
37
+ copyEndpointOnNewTab: boolean;
38
+ tabName: string;
39
+ corsProxy: string | undefined;
40
+ endpointCatalogueOptions: EndpointSelectConfig<EndpointObject>;
41
+ //The function allows us to modify the config before we pass it on to a tab
42
+ populateFromUrl: boolean | ((configFromUrl: PersistedTabJson) => PersistedTabJson);
43
+ autoAddOnInit: boolean;
44
+ persistenceId: ((yasr: Yasgui) => string) | string | null;
45
+ persistenceLabelConfig: string;
46
+ persistenceLabelResponse: string;
47
+ persistencyExpire: number;
48
+ yasqe: Partial<YasqeConfig>;
49
+ yasr: YasrConfig;
50
+ requestConfig: YasguiRequestConfig;
51
+ contextMenuContainer: HTMLElement | undefined;
52
+ nonSslDomain?: string;
53
+ }
54
+ export type PartialConfig = {
55
+ [P in keyof Config]?: Config[P] extends object ? Partial<Config[P]> : Config[P];
56
+ };
57
+
58
+ export type TabJson = PersistedTabJson;
59
+
60
+ export interface Yasgui {
61
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
62
+
63
+ on(event: "tabSelect", listener: (instance: Yasgui, newTabId: string) => void): this;
64
+ emit(event: "tabSelect", instance: Yasgui, newTabId: string): boolean;
65
+ on(event: "tabClose", listener: (instance: Yasgui, tab: Tab) => void): this;
66
+ emit(event: "tabClose", instance: Yasgui, tab: Tab): boolean;
67
+ on(event: "query", listener: (instance: Yasgui, tab: Tab) => void): this;
68
+ emit(event: "query", instance: Yasgui, tab: Tab): boolean;
69
+ on(event: "queryBefore", listener: (instance: Yasgui, tab: Tab) => void): this;
70
+ emit(event: "queryBefore", instance: Yasgui, tab: Tab): boolean;
71
+ on(event: "queryAbort", listener: (instance: Yasgui, tab: Tab) => void): this;
72
+ emit(event: "queryAbort", instance: Yasgui, tab: Tab): boolean;
73
+ on(event: "queryResponse", listener: (instance: Yasgui, tab: Tab) => void): this;
74
+ emit(event: "queryResponse", instance: Yasgui, tab: Tab): boolean;
75
+ on(event: "tabChange", listener: (instance: Yasgui, tab: Tab) => void): this;
76
+ emit(event: "tabChange", instance: Yasgui, tab: Tab): boolean;
77
+ on(event: "tabAdd", listener: (instance: Yasgui, newTabId: string) => void): this;
78
+ emit(event: "tabAdd", instance: Yasgui, newTabId: string): boolean;
79
+ on(event: "tabOrderChanged", listener: (instance: Yasgui, tabList: string[]) => void): this;
80
+ emit(event: "tabOrderChanged", instance: Yasgui, tabList: string[]): boolean;
81
+ on(event: "fullscreen-enter", listener: (instance: Yasgui) => void): this;
82
+ emit(event: "fullscreen-enter", instance: Yasgui): boolean;
83
+ on(event: "fullscreen-leave", listener: (instance: Yasgui) => void): this;
84
+ emit(event: "fullscreen-leave", instance: Yasgui): boolean;
85
+ on(event: "endpointHistoryChange", listener: (instance: Yasgui, history: string[]) => void): this;
86
+ emit(event: "endpointHistoryChange", instance: Yasgui, history: string[]): boolean;
87
+ on(event: "autocompletionShown", listener: (instance: Yasgui, tab: Tab, widget: any) => void): this;
88
+ emit(event: "autocompletionShown", instance: Yasgui, tab: Tab, widget: any): boolean;
89
+ on(event: "autocompletionClose", listener: (instance: Yasgui, tab: Tab) => void): this;
90
+ emit(event: "autocompletionClose", instance: Yasgui, tab: Tab): boolean;
91
+ }
92
+ export class Yasgui extends EventEmitter {
93
+ public rootEl: HTMLDivElement;
94
+ public tabElements: TabElements;
95
+ public _tabs: { [tabId: string]: Tab } = {};
96
+ public tabPanelsEl: HTMLDivElement;
97
+ public config: Config;
98
+ public persistentConfig: PersistentConfig;
99
+ public static Tab = Tab;
100
+ constructor(parent: HTMLElement, config: PartialConfig) {
101
+ super();
102
+ this.rootEl = document.createElement("div");
103
+ addClass(this.rootEl, "yasgui");
104
+ parent.appendChild(this.rootEl);
105
+
106
+ this.config = merge({}, Yasgui.defaults, config);
107
+ this.persistentConfig = new PersistentConfig(this);
108
+
109
+ this.tabElements = new TabElements(this);
110
+ this.tabPanelsEl = document.createElement("div");
111
+
112
+ this.rootEl.appendChild(this.tabElements.drawTabsList());
113
+ this.rootEl.appendChild(this.tabPanelsEl);
114
+ let executeIdAfterInit: string | undefined;
115
+ let optionsFromUrl: PersistedTabJson | undefined;
116
+ if (this.config.populateFromUrl) {
117
+ optionsFromUrl = shareLink.getConfigFromUrl(Tab.getDefaults(this));
118
+ if (optionsFromUrl) {
119
+ const tabId = this.findTabIdForConfig(optionsFromUrl);
120
+ if (tabId) {
121
+ // when a config is already present,
122
+ const persistentYasr = this.persistentConfig.getTab(tabId).yasr;
123
+ this.persistentConfig.getTab(tabId).yasr = {
124
+ // Override the settings
125
+ settings: optionsFromUrl.yasr.settings,
126
+ // Keep the old response to save data/time
127
+ response: persistentYasr.response,
128
+ };
129
+ this.persistentConfig.setActive(tabId);
130
+ if (!persistentYasr.response) {
131
+ //we did have a tab already open for this link, but there wasnt a response
132
+ //probably, it's too large to put in local storage
133
+ //so, lets make sure we execute the query
134
+ executeIdAfterInit = tabId;
135
+ }
136
+ } else {
137
+ this.persistentConfig.setTab(
138
+ optionsFromUrl.id,
139
+ typeof this.config.populateFromUrl === "function"
140
+ ? this.config.populateFromUrl(optionsFromUrl)
141
+ : optionsFromUrl,
142
+ );
143
+ executeIdAfterInit = optionsFromUrl.id;
144
+ }
145
+ }
146
+ }
147
+ const tabs = this.persistentConfig.getTabs();
148
+ if (!tabs.length && this.config.autoAddOnInit) {
149
+ const newTab = this.addTab(true);
150
+ this.persistentConfig.setActive(newTab.getId());
151
+ this.emit("tabChange", this, newTab);
152
+ } else {
153
+ for (const tabId of tabs) {
154
+ this._tabs[tabId] = new Tab(this, this.persistentConfig.getTab(tabId));
155
+ this._registerTabListeners(this._tabs[tabId]);
156
+ // this.tabs[tabId].on("close", tab => this.closeTabId(tab.getId()));
157
+ this.tabElements.drawTab(tabId);
158
+ }
159
+ const activeTabId = this.persistentConfig.getActiveId();
160
+ if (activeTabId) {
161
+ this.markTabSelected(activeTabId);
162
+ if (executeIdAfterInit && executeIdAfterInit === activeTabId) {
163
+ (this.getTab(activeTabId) as Tab).query().catch(() => {});
164
+ }
165
+ // }
166
+ }
167
+ }
168
+ }
169
+ public hasFullscreen(fullscreen: boolean) {
170
+ if (fullscreen) {
171
+ this.emit("fullscreen-enter", this);
172
+ addClass(this.rootEl, "hasFullscreen");
173
+ } else {
174
+ this.emit("fullscreen-leave", this);
175
+ removeClass(this.rootEl, "hasFullscreen");
176
+ }
177
+ }
178
+ public getStorageId(label: string, getter?: Config["persistenceId"]): string | undefined {
179
+ const persistenceId = getter || this.config.persistenceId;
180
+ if (!persistenceId) return undefined;
181
+ if (typeof persistenceId === "string") return persistenceId + "_" + label;
182
+ return persistenceId(this) + "_" + label;
183
+ }
184
+ public createTabName(name?: string, i: number = 0) {
185
+ if (!name) name = this.config.tabName;
186
+ var fullName = name + (i > 0 ? " " + i : "");
187
+ if (this.tabNameTaken(fullName)) fullName = this.createTabName(name, i + 1);
188
+ return fullName;
189
+ }
190
+ public tabNameTaken(name: string) {
191
+ return find(this._tabs, (tab) => tab.getName() === name);
192
+ }
193
+ public getTab(tabId?: string): Tab | undefined {
194
+ if (tabId) {
195
+ return this._tabs[tabId];
196
+ }
197
+ const currentTabId = this.persistentConfig.currentId();
198
+ if (currentTabId) return this._tabs[currentTabId];
199
+ }
200
+
201
+ //only handle UI interaction, don't emit or store anything
202
+ private markTabSelected(tabId: string): boolean {
203
+ if (!this.persistentConfig.getTab(tabId)) {
204
+ //there is no tab config for this id. We _probably_ deleted a tab by pressing 'x', which fires the 'selectTab'
205
+ //event after. I.e., nothing to select anymore, and we should just ignore this
206
+ return false;
207
+ }
208
+ //mark tab active
209
+ this.tabElements.selectTab(tabId);
210
+
211
+ //draw tab content
212
+ if (!this._tabs[tabId]) {
213
+ this._tabs[tabId] = new Tab(this, Tab.getDefaults(this));
214
+ }
215
+ this._tabs[tabId].show();
216
+ for (const otherTabId in this._tabs) {
217
+ if (otherTabId !== tabId) this._tabs[otherTabId].hide();
218
+ }
219
+ return true;
220
+ }
221
+ public selectTabId(tabId: string) {
222
+ const tab = this.getTab();
223
+ if (tab && tab.getId() !== tabId) {
224
+ if (this.markTabSelected(tabId)) {
225
+ //emit
226
+ this.emit("tabSelect", this, tabId);
227
+ this.persistentConfig.setActive(tabId);
228
+ }
229
+ }
230
+ return tab;
231
+ }
232
+ /**
233
+ * Checks if two persistent tab configuration are the same based.
234
+ * It isnt a strict equality, as falsy values (e.g. a header that isnt set in one tabjson) isnt taken into consideration
235
+ * Things like the yasr response are also not taken into consideration
236
+ * @param tab1 Base comparable object
237
+ * @param tab2 Second comparable object
238
+ */
239
+ private tabConfigEquals(tab1: PersistedTabJson, tab2: PersistedTabJson): boolean {
240
+ let sameRequest = true;
241
+
242
+ /**
243
+ * Check request config
244
+ */
245
+ let key: keyof RequestConfig<Yasgui>;
246
+ for (key in tab1.requestConfig) {
247
+ if (!tab1.requestConfig[key]) continue;
248
+ if (!isEqual(tab2.requestConfig[key], tab1.requestConfig[key])) {
249
+ sameRequest = false;
250
+ }
251
+ }
252
+ /**
253
+ * Check yasqe settings
254
+ */
255
+ if (sameRequest) {
256
+ sameRequest = (<Array<keyof PersistedTabJson["yasqe"]>>["endpoint", "value"]).every(
257
+ (key) => tab1.yasqe[key] === tab2.yasqe[key],
258
+ );
259
+ }
260
+
261
+ /**
262
+ * Check yasr settings
263
+ */
264
+ if (sameRequest) {
265
+ sameRequest =
266
+ tab1.yasr.settings.selectedPlugin === tab2.yasr.settings.selectedPlugin &&
267
+ isEqual(
268
+ tab1.yasr.settings.pluginsConfig?.[tab1.yasr.settings?.selectedPlugin || ""],
269
+ tab2.yasr.settings.pluginsConfig?.[tab2.yasr.settings?.selectedPlugin || ""],
270
+ );
271
+ }
272
+
273
+ return sameRequest && tab1.name === tab2.name;
274
+ }
275
+ private findTabIdForConfig(tabConfig: PersistedTabJson) {
276
+ return this.persistentConfig.getTabs().find((tabId) => {
277
+ const tab = this.persistentConfig.getTab(tabId);
278
+ return this.tabConfigEquals(tab, tabConfig);
279
+ });
280
+ }
281
+
282
+ private _registerTabListeners(tab: Tab) {
283
+ tab.on("change", (tab) => this.emit("tabChange", this, tab));
284
+ tab.on("query", (tab) => this.emit("query", this, tab));
285
+ tab.on("queryBefore", (tab) => this.emit("queryBefore", this, tab));
286
+ tab.on("queryAbort", (tab) => this.emit("queryAbort", this, tab));
287
+ tab.on("queryResponse", (tab) => this.emit("queryResponse", this, tab));
288
+ tab.on("autocompletionShown", (tab, widget) => this.emit("autocompletionShown", this, tab, widget));
289
+ tab.on("autocompletionClose", (tab) => this.emit("autocompletionClose", this, tab));
290
+ }
291
+ public _setPanel(panelId: string, panel: HTMLDivElement) {
292
+ for (const id in this._tabs) {
293
+ if (id !== panelId) this._tabs[id].hide();
294
+ }
295
+ this.tabPanelsEl.appendChild(panel);
296
+ }
297
+ public _removePanel(panel: HTMLDivElement | undefined) {
298
+ if (panel) this.tabPanelsEl.removeChild(panel);
299
+ }
300
+ /**
301
+ * Adds a tab to yasgui
302
+ * @param setActive if the tab should become active when added
303
+ * @param [partialTabConfig] config to add to the Tab
304
+ * @param [opts] extra options, atIndex, at which position the tab should be added, avoidDuplicateTabs: if the config already exists make that tab active
305
+ *
306
+ * @returns tab
307
+ */
308
+ public addTab(
309
+ setActive: boolean,
310
+ partialTabConfig?: Partial<PersistedTabJson>,
311
+ opts: { atIndex?: number; avoidDuplicateTabs?: boolean } = {},
312
+ ): Tab {
313
+ const tabConfig = merge({}, Tab.getDefaults(this), partialTabConfig);
314
+ if (tabConfig.id && this.getTab(tabConfig.id)) {
315
+ throw new Error("Duplicate tab ID");
316
+ }
317
+ // Check if we should copy the endpoint in the new tab and only copy if the tabConfig doesn't contain an endpoint
318
+ if (this.config.copyEndpointOnNewTab && !partialTabConfig?.requestConfig?.endpoint) {
319
+ const currentTab = this.getTab();
320
+ if (currentTab) {
321
+ tabConfig.requestConfig.endpoint = currentTab.getEndpoint();
322
+ }
323
+ }
324
+ if (opts.avoidDuplicateTabs) {
325
+ const foundTabId = this.findTabIdForConfig(tabConfig);
326
+ if (foundTabId) {
327
+ return this.selectTabId(foundTabId) as Tab;
328
+ }
329
+ }
330
+ const tabId = tabConfig.id;
331
+ const index = opts.atIndex;
332
+ this.persistentConfig.addToTabList(tabId, index);
333
+ this.emit("tabAdd", this, tabId);
334
+ this._tabs[tabId] = new Tab(this, tabConfig);
335
+ this.emit("tabChange", this, this._tabs[tabId]); //do emit, so the default config is persisted
336
+
337
+ this.tabElements.addTab(tabId, index);
338
+ this._registerTabListeners(this._tabs[tabId]);
339
+ if (setActive) {
340
+ this.persistentConfig.setActive(tabId);
341
+ this._tabs[tabId].show();
342
+ }
343
+ return this._tabs[tabId];
344
+ }
345
+ public restoreLastTab() {
346
+ const config = this.persistentConfig.retrieveLastClosedTab();
347
+ if (config) {
348
+ this.addTab(true, config.tab, { atIndex: config.index });
349
+ }
350
+ }
351
+ public destroy() {
352
+ this.removeAllListeners();
353
+ this.tabElements.destroy();
354
+ for (const tabId in this._tabs) {
355
+ const tab = this._tabs[tabId];
356
+ tab.destroy();
357
+ }
358
+ this._tabs = {};
359
+
360
+ while (this.rootEl.firstChild) this.rootEl.firstChild.remove();
361
+ }
362
+ public static linkUtils = shareLink;
363
+ public static Yasr = Yasr;
364
+ public static Yasqe = Yasqe;
365
+ public static defaults = initializeDefaults();
366
+ public static corsEnabled: { [endpoint: string]: boolean } = {};
367
+ }
368
+
369
+ export function getRandomId() {
370
+ return Math.random().toString(36).substring(7);
371
+ }
372
+
373
+ export default Yasgui;
@@ -0,0 +1,234 @@
1
+ const JsUri = require("jsuri");
2
+
3
+ import { default as Tab, PersistedJson } from "./Tab";
4
+ import Yasr from "@matdata/yasr";
5
+ import { PlainRequestConfig } from "@matdata/yasqe";
6
+ import { getAsValue } from "@matdata/yasgui-utils";
7
+ var getUrlParams = function (_url?: string) {
8
+ var urlFromWindow = false;
9
+ if (!_url) {
10
+ _url = window.location.href;
11
+ urlFromWindow = true;
12
+ }
13
+ var url = new JsUri(_url);
14
+ if (url.anchor().length > 0) {
15
+ //firefox does some decoding if we're using window.location.hash (e.g. the + sign in contentType settings)
16
+ //Don't want this. So simply get the hash string ourselves
17
+ url.query(url.anchor());
18
+ if (urlFromWindow) window.location.hash = ""; //clear hash
19
+ }
20
+ return url;
21
+ };
22
+
23
+ export type RequestArgs = { [argName: string]: string | string[] };
24
+ export function appendArgsToUrl(_url: string, args: RequestArgs): string {
25
+ var url = new JsUri(_url);
26
+ for (const arg in args) {
27
+ const val = args[arg];
28
+ if (Array.isArray(val)) {
29
+ for (const subVal of val) {
30
+ url.addQueryParam(arg, subVal);
31
+ }
32
+ } else {
33
+ url.addQueryParam(arg, val);
34
+ }
35
+ }
36
+ return url.toString();
37
+ }
38
+ export function createShareLink(forUrl: string, tab: Tab) {
39
+ const currentUrl = new JsUri(forUrl);
40
+ const tmpUrl = new JsUri();
41
+ const configObject = createShareConfig(tab);
42
+ let key: keyof ShareConfigObject; // Need to specify here because left hand side of a for..in cannot be typed
43
+ for (key in configObject) {
44
+ if (!configObject.hasOwnProperty(key)) continue;
45
+ if (key === "namedGraphs") {
46
+ configObject.namedGraphs.forEach((ng) => tmpUrl.addQueryParam("namedGraph", ng));
47
+ } else if (key === "defaultGraphs") {
48
+ configObject.defaultGraphs.forEach((dg) => tmpUrl.addQueryParam("defaultGraph", dg));
49
+ } else if (key === "args") {
50
+ const args = getAsValue(configObject.args, tab.yasgui);
51
+ args.forEach((arg) => tmpUrl.addQueryParam(arg.name, arg.value));
52
+ } else if (typeof configObject[key] === "object") {
53
+ if (configObject[key]) tmpUrl.addQueryParam(key, JSON.stringify(configObject[key]));
54
+ } else {
55
+ if (configObject[key]) tmpUrl.addQueryParam(key, configObject[key]);
56
+ }
57
+ }
58
+
59
+ //extend existing link, so first fetch current arguments. But: make sure we don't include items already used in share link
60
+ // if (window.location.hash.length > 1) {
61
+ const currentUrlParams = getUrlParams(forUrl);
62
+ const currentParams: [string, string][] = (<any>currentUrlParams).queryPairs;
63
+ currentParams.forEach(function (paramPair) {
64
+ if (!tmpUrl.hasQueryParam(paramPair[0])) {
65
+ tmpUrl.addQueryParam(paramPair[0], paramPair[1]);
66
+ }
67
+ });
68
+ // }
69
+
70
+ currentUrl.anchor(tmpUrl.query().substr(1));
71
+ return currentUrl.toString();
72
+ }
73
+ export type ShareConfigObject = {
74
+ query: string;
75
+ endpoint: string;
76
+ requestMethod: PlainRequestConfig["method"];
77
+ tabTitle: string;
78
+ headers: PlainRequestConfig["headers"];
79
+ contentTypeConstruct: string;
80
+ contentTypeSelect: string;
81
+ args: PlainRequestConfig["args"];
82
+ namedGraphs: PlainRequestConfig["namedGraphs"];
83
+ defaultGraphs: PlainRequestConfig["defaultGraphs"];
84
+ outputFormat?: string;
85
+ outputSettings: any;
86
+ };
87
+
88
+ export function createShareConfig(tab: Tab): ShareConfigObject {
89
+ const yasgui = tab.yasgui;
90
+ const requestConfig = tab.getRequestConfig();
91
+ const yasrPersistentSetting = tab.getPersistedJson().yasr.settings;
92
+ return {
93
+ query: tab.getQuery(),
94
+ endpoint: tab.getEndpoint(),
95
+ requestMethod: getAsValue(requestConfig.method, yasgui),
96
+ tabTitle: tab.getName(),
97
+ // headers: isFunction(requestConfig.headers) ? requestConfig.headers(tab.yasgui) : requestConfig.headers,
98
+ headers: getAsValue(requestConfig.headers, yasgui),
99
+ contentTypeConstruct: getAsValue(requestConfig.acceptHeaderGraph, yasgui),
100
+ contentTypeSelect: getAsValue(requestConfig.acceptHeaderSelect, yasgui),
101
+ args: getAsValue(requestConfig.args, yasgui),
102
+ namedGraphs: getAsValue(requestConfig.namedGraphs, yasgui),
103
+ defaultGraphs: getAsValue(requestConfig.defaultGraphs, yasgui),
104
+ outputFormat: yasrPersistentSetting.selectedPlugin,
105
+ outputSettings:
106
+ yasrPersistentSetting.pluginsConfig && yasrPersistentSetting.selectedPlugin
107
+ ? yasrPersistentSetting.pluginsConfig[yasrPersistentSetting.selectedPlugin]
108
+ : undefined,
109
+ };
110
+ }
111
+
112
+ export function getConfigFromUrl(defaults: PersistedJson, _url?: string): PersistedJson | undefined {
113
+ const options = defaults;
114
+
115
+ var url = getUrlParams(_url);
116
+ var hasQuery = false;
117
+ const currentParams: [string, string][] = (<any>url).queryPairs;
118
+ var pluginsConfig: any;
119
+ currentParams.forEach(function ([key, value]) {
120
+ if (key === "query") {
121
+ hasQuery = true;
122
+ options.yasqe.value = value;
123
+ } else if (key === "outputFormat" && value.length) {
124
+ if (Yasr.plugins[value]) {
125
+ options.yasr.settings.selectedPlugin = value;
126
+ } else {
127
+ console.warn(`Output format plugin "${value}" not found`);
128
+ }
129
+ } else if (key == "outputSettings") {
130
+ pluginsConfig = JSON.parse(value);
131
+ } else if (key == "contentTypeConstruct") {
132
+ options.requestConfig.acceptHeaderGraph = value;
133
+ } else if (key == "contentTypeSelect") {
134
+ options.requestConfig.acceptHeaderSelect = value;
135
+ } else if (key == "endpoint") {
136
+ options.requestConfig.endpoint = value;
137
+ } else if (key == "requestMethod") {
138
+ options.requestConfig.method = <any>value;
139
+ } else if (key == "tabTitle") {
140
+ options.name = value;
141
+ } else if (key == "namedGraph") {
142
+ if (!Array.isArray(options.requestConfig.namedGraphs)) options.requestConfig.namedGraphs = [];
143
+ options.requestConfig.namedGraphs.push(value);
144
+ } else if (key == "defaultGraph") {
145
+ if (!Array.isArray(options.requestConfig.defaultGraphs)) options.requestConfig.defaultGraphs = [];
146
+ options.requestConfig.defaultGraphs.push(value);
147
+ } else if (key == "headers") {
148
+ if (!options.requestConfig.headers) options.requestConfig.headers = {};
149
+ options.requestConfig.headers = JSON.parse(value);
150
+ } else {
151
+ //regular arguments. So store them as regular arguments
152
+ if (!options.requestConfig.args) options.requestConfig.args = [];
153
+ (options.requestConfig.args as Array<{ name: string; value: string }>).push({ name: key, value: value });
154
+ }
155
+ });
156
+ //Only know where to store the plugins config after we've saved the selected plugin
157
+ //i.e., do this after the previous loop
158
+ if (pluginsConfig && options.yasr.settings.selectedPlugin && options.yasr.settings.pluginsConfig) {
159
+ options.yasr.settings.pluginsConfig[options.yasr.settings.selectedPlugin] = pluginsConfig;
160
+ }
161
+ if (hasQuery) {
162
+ return options;
163
+ }
164
+ }
165
+
166
+ export function queryCatalogConfigToTabConfig<Q extends QueryCatalogConfig>(
167
+ catalogConfig: Q,
168
+ defaults?: PersistedJson,
169
+ ): PersistedJson {
170
+ const options = defaults || Tab.getDefaults();
171
+ if (catalogConfig.service) {
172
+ options.requestConfig.endpoint = catalogConfig.service;
173
+ }
174
+ if (catalogConfig.requestConfig) {
175
+ if (catalogConfig.requestConfig.payload) {
176
+ if (catalogConfig.requestConfig.payload.query) {
177
+ options.yasqe.value = catalogConfig.requestConfig.payload.query;
178
+ }
179
+ if (catalogConfig.requestConfig.payload["default-graph-uri"]) {
180
+ options.requestConfig.defaultGraphs = Array.isArray(catalogConfig.requestConfig.payload["default-graph-uri"])
181
+ ? catalogConfig.requestConfig.payload["default-graph-uri"]
182
+ : [catalogConfig.requestConfig.payload["default-graph-uri"]];
183
+ }
184
+ if (catalogConfig.requestConfig.payload["named-graph-uri"]) {
185
+ options.requestConfig.namedGraphs = Array.isArray(catalogConfig.requestConfig.payload["named-graph-uri"])
186
+ ? catalogConfig.requestConfig.payload["named-graph-uri"]
187
+ : [catalogConfig.requestConfig.payload["named-graph-uri"]];
188
+ }
189
+ }
190
+ if (catalogConfig.requestConfig.headers) {
191
+ options.requestConfig.headers = catalogConfig.requestConfig.headers;
192
+ }
193
+ }
194
+ if (catalogConfig.renderConfig) {
195
+ if (catalogConfig.renderConfig.output) {
196
+ if (Yasr.plugins[catalogConfig.renderConfig.output]) {
197
+ options.yasr.settings.selectedPlugin = catalogConfig.renderConfig.output;
198
+ } else {
199
+ console.warn(`Output format plugin "${catalogConfig.renderConfig.output}" not found`);
200
+ }
201
+ }
202
+ if (catalogConfig.renderConfig.settings) {
203
+ if (Yasr.plugins[catalogConfig.renderConfig.output] && options.yasr.settings.pluginsConfig) {
204
+ options.yasr.settings.pluginsConfig[catalogConfig.renderConfig.output] = catalogConfig.renderConfig.settings;
205
+ } else {
206
+ console.warn(`Output format plugin "${catalogConfig.renderConfig.output}" not found, cannot apply settings`);
207
+ }
208
+ }
209
+ }
210
+ if (catalogConfig.name) {
211
+ options.name = catalogConfig.name;
212
+ }
213
+ return options;
214
+ }
215
+
216
+ export interface QueryCatalogConfig {
217
+ service: string;
218
+ name: string;
219
+ description: string;
220
+ requestConfig?: {
221
+ payload: {
222
+ query: string;
223
+ "default-graph-uri"?: string | string[];
224
+ "named-graph-uri"?: string | string[];
225
+ };
226
+ headers?: {
227
+ [key: string]: string;
228
+ };
229
+ };
230
+ renderConfig?: {
231
+ output: string;
232
+ settings?: any;
233
+ };
234
+ }
package/src/tab.scss ADDED
@@ -0,0 +1,61 @@
1
+ .yasgui {
2
+ .tabPanel {
3
+ display: none;
4
+ position: relative;
5
+ &.active {
6
+ display: block;
7
+ }
8
+
9
+ // Hide editor wrapper when yasr is in fullscreen
10
+ &:has(.yasr.fullscreen) .editorwrapper {
11
+ display: none;
12
+ }
13
+
14
+ // When yasqe is fullscreen, keep controlbar visible
15
+ &:has(.yasqe.fullscreen) .controlbar {
16
+ position: fixed;
17
+ top: 50px;
18
+ left: 0;
19
+ right: 0;
20
+ z-index: 9999;
21
+ background: white;
22
+ border-bottom: 1px solid #ddd;
23
+ padding: 5px;
24
+ }
25
+ }
26
+ .yasr {
27
+ margin-top: 5px;
28
+ }
29
+
30
+ .tabContextButton {
31
+ border: none;
32
+ background: none;
33
+ align-self: center;
34
+ padding-left: 10px;
35
+ cursor: pointer;
36
+ color: #505050;
37
+ fill: #505050;
38
+
39
+ .svgImg {
40
+ width: 15px;
41
+ height: 15px;
42
+ font-family: initial; //font families can slightly misalign svgs with the .svgimg div
43
+ }
44
+ // IE11 Needs this specified otherwise it will not resize the svg
45
+ svg {
46
+ max-width: 15px;
47
+ max-height: 15px;
48
+ }
49
+
50
+ &:hover {
51
+ color: black;
52
+ fill: black;
53
+ }
54
+ }
55
+
56
+ .controlbar {
57
+ display: flex;
58
+ align-content: center;
59
+ max-height: 35px;
60
+ }
61
+ }