flexdesk 0.17.14 → 0.17.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/CHANGELOG.md +39 -0
- package/css/base.css +237 -8
- package/css/flexdesk.css +344 -17
- package/css/overrides.css +6 -0
- package/dist/charts.js +104 -34
- package/dist/charts.js.map +3 -3
- package/dist/{chunk-2PM6ZMNS.js → chunk-2Z2ENHR3.js} +2 -2
- package/dist/{chunk-IG74S3ZH.js → chunk-7JI7HHSY.js} +2 -2
- package/dist/{chunk-TLIV6QSU.js → chunk-7OL6F2AM.js} +3 -3
- package/dist/{chunk-MADMGRX2.js → chunk-PGZ4EHSE.js} +156 -9
- package/dist/chunk-PGZ4EHSE.js.map +7 -0
- package/dist/{chunk-ZMH3OC7H.js → chunk-XJNADRGR.js} +4 -2
- package/dist/chunk-XJNADRGR.js.map +7 -0
- package/dist/flexdesk.css +344 -17
- package/dist/flow.js +3 -3
- package/dist/tiles.js +84 -9
- package/dist/tiles.js.map +2 -2
- package/dist/widgets.js +448 -5
- package/dist/widgets.js.map +4 -4
- package/dist/wm.js +110 -19
- package/dist/wm.js.map +2 -2
- package/docs/README.md +1 -1
- package/docs/components/charts.md +70 -3
- package/docs/components/forms-and-dialogs.md +80 -2
- package/docs/components/menus.md +85 -1
- package/docs/components/shell.md +52 -0
- package/docs/components/slide-out-panel.md +15 -0
- package/docs/components/tiles.md +37 -0
- package/package.json +1 -1
- package/src/charts/plot_config_editor.js +125 -29
- package/src/tiles/tile_base.js +48 -2
- package/src/tiles/tile_grid.js +42 -1
- package/src/tiling/kind_taxonomy.js +45 -0
- package/src/tiling/tile_breadcrumb.js +12 -4
- package/src/tiling/wm.js +86 -11
- package/src/ui/components/category_picker.js +556 -0
- package/src/ui/components/computing_status_window.js +3 -0
- package/src/ui/components/confirm_dialog.js +3 -0
- package/src/ui/components/managed_window.js +204 -9
- package/src/ui/components/modal.js +11 -2
- package/src/ui/components/wizard.js +4 -1
- package/widgets.js +2 -1
- package/dist/chunk-MADMGRX2.js.map +0 -7
- package/dist/chunk-ZMH3OC7H.js.map +0 -7
- /package/dist/{chunk-2PM6ZMNS.js.map → chunk-2Z2ENHR3.js.map} +0 -0
- /package/dist/{chunk-IG74S3ZH.js.map → chunk-7JI7HHSY.js.map} +0 -0
- /package/dist/{chunk-TLIV6QSU.js.map → chunk-7OL6F2AM.js.map} +0 -0
package/dist/wm.js
CHANGED
|
@@ -8,14 +8,14 @@ import {
|
|
|
8
8
|
} from "./chunk-REJ5HLIM.js";
|
|
9
9
|
import {
|
|
10
10
|
showContextMenu
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7JI7HHSY.js";
|
|
12
12
|
import {
|
|
13
13
|
openForm
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XJNADRGR.js";
|
|
15
15
|
import {
|
|
16
16
|
ManagedWindow,
|
|
17
17
|
isRowActivation
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PGZ4EHSE.js";
|
|
19
19
|
import "./chunk-HNU6MM2B.js";
|
|
20
20
|
import {
|
|
21
21
|
NotebookTabBar
|
|
@@ -2642,6 +2642,28 @@ function createTaxonomy({ kinds, root } = {}) {
|
|
|
2642
2642
|
`createTaxonomy: '${kind}'.single must be true or a prop name`
|
|
2643
2643
|
);
|
|
2644
2644
|
}
|
|
2645
|
+
if (def.window != null) {
|
|
2646
|
+
const w = def.window;
|
|
2647
|
+
const bad = (v) => v != null && !(typeof v === "number" && Number.isFinite(v) && v > 0);
|
|
2648
|
+
if (typeof w !== "object" || Array.isArray(w) || bad(w.width) || bad(w.height)) {
|
|
2649
|
+
throw new TypeError(
|
|
2650
|
+
`createTaxonomy: '${kind}'.window must be { width?, height? } in positive px`
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
if (def.windowOnly != null && typeof def.windowOnly !== "boolean") {
|
|
2655
|
+
throw new TypeError(`createTaxonomy: '${kind}'.windowOnly must be true or false`);
|
|
2656
|
+
}
|
|
2657
|
+
if (def.windowOnly && def.isTopNav) {
|
|
2658
|
+
throw new Error(
|
|
2659
|
+
`createTaxonomy: '${kind}' is a top-nav page and cannot be windowOnly \u2014 a page lives in tiles`
|
|
2660
|
+
);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
if (kinds[root].windowOnly) {
|
|
2664
|
+
throw new Error(
|
|
2665
|
+
`createTaxonomy: the root kind '${root}' cannot be windowOnly \u2014 every new pane, tab and desktop is seeded with it`
|
|
2666
|
+
);
|
|
2645
2667
|
}
|
|
2646
2668
|
if (kinds[root].single) {
|
|
2647
2669
|
throw new Error(
|
|
@@ -2720,6 +2742,11 @@ function createTaxonomy({ kinds, root } = {}) {
|
|
|
2720
2742
|
const v = props?.[by];
|
|
2721
2743
|
return `${kind}\0${v == null ? "" : String(v)}`;
|
|
2722
2744
|
};
|
|
2745
|
+
const isWindowOnly = (kind) => _kinds[kind]?.windowOnly === true;
|
|
2746
|
+
const windowSize = (kind) => {
|
|
2747
|
+
const w = _kinds[kind]?.window;
|
|
2748
|
+
return w ? { width: w.width ?? null, height: w.height ?? null } : null;
|
|
2749
|
+
};
|
|
2723
2750
|
const singleReason = (kind) => `${_kinds[kind]?.label || kind} is open once: use the one that is open`;
|
|
2724
2751
|
return Object.freeze({
|
|
2725
2752
|
root,
|
|
@@ -2735,7 +2762,9 @@ function createTaxonomy({ kinds, root } = {}) {
|
|
|
2735
2762
|
topNavEntries,
|
|
2736
2763
|
isSingle,
|
|
2737
2764
|
instanceKey,
|
|
2738
|
-
singleReason
|
|
2765
|
+
singleReason,
|
|
2766
|
+
isWindowOnly,
|
|
2767
|
+
windowSize
|
|
2739
2768
|
});
|
|
2740
2769
|
}
|
|
2741
2770
|
|
|
@@ -3471,7 +3500,11 @@ function mountTileBreadcrumb(kind, props, ctx) {
|
|
|
3471
3500
|
const rootCrumb = ctx?.rootCrumb || null;
|
|
3472
3501
|
if (!taxonomy) {
|
|
3473
3502
|
console.error("[breadcrumb] no taxonomy in ctx \u2014 cannot render");
|
|
3474
|
-
|
|
3503
|
+
const el = document.createElement("nav");
|
|
3504
|
+
el.className = "twm-topbar-breadcrumb twm-tile-breadcrumb";
|
|
3505
|
+
el.hidden = true;
|
|
3506
|
+
return { el, refresh: () => {
|
|
3507
|
+
}, destroy: () => {
|
|
3475
3508
|
} };
|
|
3476
3509
|
}
|
|
3477
3510
|
const root = document.createElement("nav");
|
|
@@ -3505,10 +3538,9 @@ function mountTileBreadcrumb(kind, props, ctx) {
|
|
|
3505
3538
|
}
|
|
3506
3539
|
};
|
|
3507
3540
|
const render = () => {
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
);
|
|
3541
|
+
const segments = _segments(kind, props, taxonomy, rootCrumb, rootLabel, navigate, trailOf());
|
|
3542
|
+
_renderInto(root, segments);
|
|
3543
|
+
root.hidden = segments.length < 2;
|
|
3512
3544
|
};
|
|
3513
3545
|
render();
|
|
3514
3546
|
let unsubscribe = null;
|
|
@@ -5458,7 +5490,11 @@ var WindowManager = class _WindowManager {
|
|
|
5458
5490
|
}
|
|
5459
5491
|
}
|
|
5460
5492
|
}
|
|
5461
|
-
const
|
|
5493
|
+
const windowOnlyDropped = this._dropWindowOnlyTabs();
|
|
5494
|
+
if (windowOnlyDropped.length) {
|
|
5495
|
+
(this.logger ?? console).warn?.(`[wm] the saved layout held ${windowOnlyDropped.length} tile tab(s) of window-only kind(s) ${[...new Set(windowOnlyDropped)].join(", ")}; they open in a window when asked for`);
|
|
5496
|
+
}
|
|
5497
|
+
const deduped = this._dropDuplicateSingles() || windowOnlyDropped.length > 0;
|
|
5462
5498
|
for (const d of this.desktops.desktops) this._canonicalize(d.tree, d);
|
|
5463
5499
|
this.renderer.tree = this.desktops.active().tree;
|
|
5464
5500
|
this.renderer.render();
|
|
@@ -5725,20 +5761,52 @@ var WindowManager = class _WindowManager {
|
|
|
5725
5761
|
}
|
|
5726
5762
|
return keys;
|
|
5727
5763
|
}
|
|
5764
|
+
/** Open a window-only kind (KindDef `windowOnly`) in its window — the one
|
|
5765
|
+
* that is open, or a new one — and say so; any other kind: false, and the
|
|
5766
|
+
* caller opens it where it asked (STORY-0127). */
|
|
5767
|
+
_openWindowOnly(kind, props) {
|
|
5768
|
+
if (!this.taxonomy.isWindowOnly?.(kind)) return false;
|
|
5769
|
+
this._navigateWindow(kind, props);
|
|
5770
|
+
return true;
|
|
5771
|
+
}
|
|
5772
|
+
/** Whether a window record holds a window-only kind: such a window never
|
|
5773
|
+
* docks into a tile (Back to tile, maximize, drag-to-dock). */
|
|
5774
|
+
_holdsWindowOnly(rec) {
|
|
5775
|
+
return !!this.taxonomy.isWindowOnly && _windowTabSpecs(rec).some((t) => this.taxonomy.isWindowOnly(t?.kind));
|
|
5776
|
+
}
|
|
5777
|
+
/** A restored layout never holds a window-only kind in a tile: its tabs,
|
|
5778
|
+
* and its tabs archived under a page, go. Windows are not restored, so
|
|
5779
|
+
* the content simply opens in a window the next time it is asked for.
|
|
5780
|
+
* Returns the kinds of the tabs that went, one entry per tab. */
|
|
5781
|
+
_dropWindowOnlyTabs() {
|
|
5782
|
+
if (!this.taxonomy.isWindowOnly) return [];
|
|
5783
|
+
const dropped = [];
|
|
5784
|
+
this._pruneRestoredTabs((t) => {
|
|
5785
|
+
if (!t || !this.taxonomy.isWindowOnly(t.kind)) return true;
|
|
5786
|
+
dropped.push(t.kind);
|
|
5787
|
+
return false;
|
|
5788
|
+
});
|
|
5789
|
+
return dropped;
|
|
5790
|
+
}
|
|
5728
5791
|
/** A restored layout keeps the FIRST instance of each single kind: later
|
|
5729
5792
|
* live tabs are dropped (the tile shows the tab that took the dropped
|
|
5730
5793
|
* one's place, or closes when it held nothing else), and so are later
|
|
5731
5794
|
* archived ones. Answers whether anything was dropped. */
|
|
5732
5795
|
_dropDuplicateSingles() {
|
|
5733
5796
|
const seen = /* @__PURE__ */ new Set();
|
|
5734
|
-
|
|
5735
|
-
const keep = (t) => {
|
|
5797
|
+
return this._pruneRestoredTabs((t) => {
|
|
5736
5798
|
const k = t ? this._instanceKey(t.kind, t.props) : null;
|
|
5737
5799
|
if (k == null) return true;
|
|
5738
5800
|
if (seen.has(k)) return false;
|
|
5739
5801
|
seen.add(k);
|
|
5740
5802
|
return true;
|
|
5741
|
-
};
|
|
5803
|
+
});
|
|
5804
|
+
}
|
|
5805
|
+
/** Drop every tab of the restored layout `keep(tab)` refuses, in the
|
|
5806
|
+
* tiles and in their archived pages; a tile left empty closes (seeding a
|
|
5807
|
+
* content tile if none is left). Returns whether anything went. */
|
|
5808
|
+
_pruneRestoredTabs(keep) {
|
|
5809
|
+
let dropped = false;
|
|
5742
5810
|
for (const d of this.desktops.desktops) {
|
|
5743
5811
|
const tree = d.tree;
|
|
5744
5812
|
for (const leaf of tree.leaves()) {
|
|
@@ -5978,6 +6046,7 @@ var WindowManager = class _WindowManager {
|
|
|
5978
6046
|
const tree = this._tree();
|
|
5979
6047
|
const prior = tree.popActiveTabHistory?.(id);
|
|
5980
6048
|
if (!prior || !prior.kind) return false;
|
|
6049
|
+
if (this._openWindowOnly(prior.kind, prior.props || {})) return true;
|
|
5981
6050
|
if (this.revealInstance(prior.kind, prior.props || {})) return true;
|
|
5982
6051
|
const curKind = tree.get(id)?.content?.kind;
|
|
5983
6052
|
const curTopNav = curKind ? this.taxonomy.topNavFor(curKind) : null;
|
|
@@ -6094,6 +6163,7 @@ var WindowManager = class _WindowManager {
|
|
|
6094
6163
|
* the leaf. Used by Backspace + breadcrumb segments + anything
|
|
6095
6164
|
* else that should walk WITHIN the tile rather than reset it. */
|
|
6096
6165
|
navigateActiveTab(leafId, kind, props = {}) {
|
|
6166
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
6097
6167
|
if (this.revealInstance(kind, props)) return;
|
|
6098
6168
|
const tree = this._tree();
|
|
6099
6169
|
const leaf = tree.get(leafId);
|
|
@@ -6148,6 +6218,7 @@ var WindowManager = class _WindowManager {
|
|
|
6148
6218
|
* tab feature shipped), the behavior is identical to the old
|
|
6149
6219
|
* setLeafContent: one tab in, one tab out. */
|
|
6150
6220
|
openInLeaf(leafId, kind, props = {}) {
|
|
6221
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
6151
6222
|
if (this.revealInstance(kind, props)) return;
|
|
6152
6223
|
const tree = this._tree();
|
|
6153
6224
|
const leaf = tree.get(leafId);
|
|
@@ -6165,6 +6236,7 @@ var WindowManager = class _WindowManager {
|
|
|
6165
6236
|
* previous mount, mounts the new kind into the same body element,
|
|
6166
6237
|
* and updates the window's title. */
|
|
6167
6238
|
openInWindow(winId, kind, props = {}) {
|
|
6239
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
6168
6240
|
if (this.revealInstance(kind, props)) return;
|
|
6169
6241
|
const rec = this._windowToLeaf.get(winId);
|
|
6170
6242
|
if (!rec) {
|
|
@@ -6204,6 +6276,7 @@ var WindowManager = class _WindowManager {
|
|
|
6204
6276
|
* If only panel tiles exist (or the tree is empty), spawn a new
|
|
6205
6277
|
* content leaf and canonicalize so the panels wrap it. */
|
|
6206
6278
|
openInPrimary(kind, props = {}) {
|
|
6279
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
6207
6280
|
if (this.revealInstance(kind, props)) return;
|
|
6208
6281
|
const tree = this._tree();
|
|
6209
6282
|
let leafId = tree.primaryLeafId();
|
|
@@ -6264,6 +6337,7 @@ var WindowManager = class _WindowManager {
|
|
|
6264
6337
|
* pane in a split never dismounts the original). Returns the new
|
|
6265
6338
|
* leaf id, or null if the leaf can't be split. */
|
|
6266
6339
|
splitLeafWith(leafId, dir, kind, props = {}, title = "") {
|
|
6340
|
+
if (this._openWindowOnly(kind, props)) return null;
|
|
6267
6341
|
if (this.revealInstance(kind, props)) return null;
|
|
6268
6342
|
const tree = this._tree();
|
|
6269
6343
|
leafId = this._contentLeafId(leafId);
|
|
@@ -6673,6 +6747,9 @@ var WindowManager = class _WindowManager {
|
|
|
6673
6747
|
canMaximize: true,
|
|
6674
6748
|
canResize: true,
|
|
6675
6749
|
modal: false,
|
|
6750
|
+
// BUG-0053. The id is minted per window and never opens again, so
|
|
6751
|
+
// geometry saved under it could never be restored.
|
|
6752
|
+
persistGeometry: false,
|
|
6676
6753
|
// C15. Dropping a promoted window on a tile PUTS IT BACK — as that
|
|
6677
6754
|
// tile's content, as a split of it, or as one of its tabs. Off
|
|
6678
6755
|
// unless the embedder asked, because it changes what a drag to an
|
|
@@ -7127,6 +7204,7 @@ var WindowManager = class _WindowManager {
|
|
|
7127
7204
|
bringBackWindow(windowId) {
|
|
7128
7205
|
const rec = this._windowToLeaf.get(windowId);
|
|
7129
7206
|
if (!rec) return false;
|
|
7207
|
+
if (this._holdsWindowOnly(rec)) return false;
|
|
7130
7208
|
const tree = this.desktops.desktops[rec.desktopIdx]?.tree;
|
|
7131
7209
|
const home = rec.homeLeafId ? tree?.get(rec.homeLeafId) : null;
|
|
7132
7210
|
if (home && home.kind === "leaf") {
|
|
@@ -7745,6 +7823,7 @@ var WindowManager = class _WindowManager {
|
|
|
7745
7823
|
dockWindowInto(windowId, target) {
|
|
7746
7824
|
const rec = this._windowToLeaf.get(windowId);
|
|
7747
7825
|
if (!rec || !target?.leafId) return false;
|
|
7826
|
+
if (this._holdsWindowOnly(rec)) return false;
|
|
7748
7827
|
rec._dock = { ...target };
|
|
7749
7828
|
rec._demoting = true;
|
|
7750
7829
|
try {
|
|
@@ -7914,7 +7993,7 @@ var WindowManager = class _WindowManager {
|
|
|
7914
7993
|
e.preventDefault();
|
|
7915
7994
|
const rec = this._windowToLeaf.get(winId);
|
|
7916
7995
|
if (!rec) return;
|
|
7917
|
-
const items = [
|
|
7996
|
+
const items = this._holdsWindowOnly(rec) ? [] : [
|
|
7918
7997
|
{ label: "Back to tile", icon: "close_fullscreen", action: "back" }
|
|
7919
7998
|
];
|
|
7920
7999
|
const targets = [...this.desktops.desktops.entries()].filter(([i, d]) => i !== rec.desktopIdx && !d.fixed);
|
|
@@ -8654,6 +8733,7 @@ var WindowManager = class _WindowManager {
|
|
|
8654
8733
|
}
|
|
8655
8734
|
/** The routing behind `navigate`, for a kind known to be registered. */
|
|
8656
8735
|
_route(kind, props, opts) {
|
|
8736
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
8657
8737
|
const { ctx = null, transient = false } = opts;
|
|
8658
8738
|
const background = !!opts.background;
|
|
8659
8739
|
let { dest = "main", newTab = false } = opts;
|
|
@@ -8722,6 +8802,8 @@ var WindowManager = class _WindowManager {
|
|
|
8722
8802
|
* source leaf — closing the window just disposes the content. */
|
|
8723
8803
|
_navigateWindow(kind, props) {
|
|
8724
8804
|
if (this.revealInstance(kind, props)) return;
|
|
8805
|
+
const size = this.taxonomy.windowSize?.(kind);
|
|
8806
|
+
const dockable = !this.taxonomy.isWindowOnly?.(kind);
|
|
8725
8807
|
const winId = `twm-mw-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 5)}`;
|
|
8726
8808
|
const contentEl = document.createElement("div");
|
|
8727
8809
|
contentEl.className = "twm-window-content";
|
|
@@ -8738,17 +8820,22 @@ var WindowManager = class _WindowManager {
|
|
|
8738
8820
|
title: mountInfo?.title || title,
|
|
8739
8821
|
icon: "web_asset",
|
|
8740
8822
|
content: contentEl,
|
|
8823
|
+
...size?.width ? { defaultWidth: size.width } : {},
|
|
8824
|
+
...size?.height ? { defaultHeight: size.height } : {},
|
|
8741
8825
|
canMinimize: true,
|
|
8742
8826
|
canMaximize: true,
|
|
8743
8827
|
canResize: true,
|
|
8744
8828
|
modal: false,
|
|
8829
|
+
// BUG-0053. The id is minted per window and never opens again, so
|
|
8830
|
+
// geometry saved under it could never be restored.
|
|
8831
|
+
persistGeometry: false,
|
|
8745
8832
|
// C15, and this is the SECOND of the two places the WM builds a
|
|
8746
8833
|
// window. Alt+N and "Open in new window" produce a window that is
|
|
8747
8834
|
// every bit as dockable as a promoted one, and a window that can be
|
|
8748
8835
|
// dragged onto a tile in one case and not the other is a rule
|
|
8749
8836
|
// nobody can learn.
|
|
8750
|
-
snap: this.snapPromotion,
|
|
8751
|
-
snapController: this.snapPromotion ? this._snapController() : null,
|
|
8837
|
+
snap: dockable && this.snapPromotion,
|
|
8838
|
+
snapController: dockable && this.snapPromotion ? this._snapController() : null,
|
|
8752
8839
|
// R1. THE PANE IS A BOX WITH `overflow: hidden`. A window contained
|
|
8753
8840
|
// to one (C21) cannot be dragged a single pixel outside it, so
|
|
8754
8841
|
// "drag a window from one tile to another" — the gesture all three
|
|
@@ -8766,9 +8853,11 @@ var WindowManager = class _WindowManager {
|
|
|
8766
8853
|
// harder. So the maximize button docks — and the separate demote
|
|
8767
8854
|
// button the WM used to inject beside it is gone, because two
|
|
8768
8855
|
// buttons for one verb is how you get a chrome nobody reads.
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8856
|
+
...dockable ? {
|
|
8857
|
+
onMaximize: () => this.bringBackWindow(winId),
|
|
8858
|
+
maximizeIcon: "close_fullscreen",
|
|
8859
|
+
maximizeTitle: "Back to tile"
|
|
8860
|
+
} : {},
|
|
8772
8861
|
onClose: () => this._onManagedWindowClosed(winId, mountInfo)
|
|
8773
8862
|
});
|
|
8774
8863
|
this._windowToLeaf.set(winId, {
|
|
@@ -8839,6 +8928,7 @@ var WindowManager = class _WindowManager {
|
|
|
8839
8928
|
* routing) but uses `appendLeafTab` so the existing content
|
|
8840
8929
|
* stays in place as a tab. */
|
|
8841
8930
|
openInTabFromContext(ctx, kind, props = {}, transient = false, background = false) {
|
|
8931
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
8842
8932
|
if (this.revealInstance(kind, props)) return;
|
|
8843
8933
|
if (ctx?.windowId && this._windowToLeaf.has(ctx.windowId)) {
|
|
8844
8934
|
this.openInWindow(ctx.windowId, kind, props);
|
|
@@ -8872,6 +8962,7 @@ var WindowManager = class _WindowManager {
|
|
|
8872
8962
|
* "Add row" button, which passes no ctx) reliably lands as a sibling
|
|
8873
8963
|
* tab in the main tile rather than swapping its content. */
|
|
8874
8964
|
openInTabInPrimary(kind, props = {}, transient = false, background = false) {
|
|
8965
|
+
if (this._openWindowOnly(kind, props)) return;
|
|
8875
8966
|
if (this.revealInstance(kind, props)) return;
|
|
8876
8967
|
const tree = this._tree();
|
|
8877
8968
|
const leafId = tree.primaryLeafId();
|