@ibgib/space-gib 0.0.34 → 0.0.35
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/client/bootstrap.mjs +1 -1
- package/dist/client/{chunk-25PXC4HP.mjs → chunk-FIAGRVBY.mjs} +1487 -468
- package/dist/client/chunk-XLQ3UCQY.mjs +53 -0
- package/dist/client/css/activity-bar.css +21 -3
- package/dist/client/css/layout.css +126 -5
- package/dist/client/index.html +6 -0
- package/dist/client/index.mjs +22 -45
- package/dist/client/privacy.html +22 -22
- package/dist/client/script.mjs +1 -1
- package/dist/server/server.mjs +3 -3
- package/package.json +6 -6
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/cosmos/seed-cosmos-workspace.mts +20 -6
- package/src/client/css/activity-bar.css +21 -3
- package/src/client/css/layout.css +126 -5
- package/src/client/dev-tools/vcs-workspace.mts +4 -4
- package/src/client/index.html +6 -0
- package/src/client/privacy.html +22 -22
- package/src/client/ui/component/changes/changes.css +413 -0
- package/src/client/ui/component/changes/changes.html +37 -0
- package/src/client/ui/component/changes/changes.mts +766 -0
- package/src/client/ui/component/changes/index.mts +9 -0
- package/src/client/ui/component/chat-view/chat-view.html +6 -58
- package/src/client/ui/component/chat-view/chat-view.mts +13 -26
- package/src/client/ui/component/clone/clone.mts +67 -39
- package/src/client/ui/component/code-editor/code-editor.css +91 -9
- package/src/client/ui/component/code-editor/code-editor.html +58 -45
- package/src/client/ui/component/code-editor/code-editor.mts +265 -49
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +1 -1
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +5 -10
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +297 -64
- package/src/client/ui/component/file-explorer/file-explorer.css +475 -11
- package/src/client/ui/component/file-explorer/file-explorer.html +45 -65
- package/src/client/ui/component/file-explorer/file-explorer.mts +1164 -98
- package/src/client/ui/component/nested-chat/chat/chat.mts +5 -90
- package/src/client/ui/component/nested-chat/nested-chat.mts +10 -8
- package/src/client/ui/component/timeline/timeline.css +16 -1
- package/src/client/ui/component/timeline/timeline.mts +37 -93
- package/src/client/ui/router/space-gib-router-helpers.mts +33 -233
- package/src/client/ui/router/space-gib-router-helpers.respec.mts +298 -122
- package/src/client/ui/router/space-gib-router-service.mts +28 -151
- package/src/client/ui/router/space-gib-router-types.mts +32 -76
- package/src/client/ui/shell/cosmic-big-bang.mts +12 -3
- package/src/client/ui/shell/space-gib-shell-service.mts +687 -119
- package/dist/client/chunk-RXWLL2AI.mjs +0 -30
|
@@ -31,6 +31,10 @@ import {
|
|
|
31
31
|
registerFileExplorerComponent, FILE_EXPLORER_COMPONENT_NAME,
|
|
32
32
|
FileExplorerComponentInstance,
|
|
33
33
|
} from "../component/file-explorer/index.mjs";
|
|
34
|
+
import {
|
|
35
|
+
registerChangesComponent, CHANGES_COMPONENT_NAME,
|
|
36
|
+
ChangesComponentInstance,
|
|
37
|
+
} from "../component/changes/index.mjs";
|
|
34
38
|
import {
|
|
35
39
|
registerTimelineComponent, TIMELINE_COMPONENT_NAME,
|
|
36
40
|
TimelineComponentInstance, TimelineItem,
|
|
@@ -69,20 +73,137 @@ import {
|
|
|
69
73
|
getSpaceGibRouterSvc,
|
|
70
74
|
SpaceGibRouteInfo,
|
|
71
75
|
SpaceGibTenant,
|
|
76
|
+
GalaxyRouteInfo,
|
|
72
77
|
RawAddrRouteInfo,
|
|
73
78
|
RawTjpRouteInfo,
|
|
74
79
|
} from "../router/index.mjs";
|
|
80
|
+
import { GalaxyPolicy } from "@ibgib/core-gib/dist/cosmology/galaxy/galaxy-types.mjs";
|
|
75
81
|
import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
|
|
76
|
-
import { prewarmPlaygroundMetaspace } from "../../cosmos/seed-cosmos-workspace.mjs";
|
|
82
|
+
import { getPlaygroundMetaspaceAndSpace, prewarmPlaygroundMetaspace } from "../../cosmos/seed-cosmos-workspace.mjs";
|
|
83
|
+
import {
|
|
84
|
+
getBranchAndRootItemInfosAndIbGibsAndSpaceFromGalaxyIbGib,
|
|
85
|
+
getFileItemFromPath,
|
|
86
|
+
getFileContent,
|
|
87
|
+
} from "@ibgib/core-gib/dist/cosmology/branching/item/item-helpers.mjs";
|
|
88
|
+
import { GalaxyIbGib_V1 } from "@ibgib/core-gib/dist/cosmology/galaxy/galaxy-types.mjs";
|
|
89
|
+
import { B2tFSGalaxyIbGib_V1 } from "@ibgib/core-gib/dist/cosmology/branching/repo/b2tfs-repo-types.mjs";
|
|
90
|
+
import { getIbGibFromSpace } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
|
|
91
|
+
import {
|
|
92
|
+
executeVcsBranch,
|
|
93
|
+
executeVcsCheckout,
|
|
94
|
+
} from "@ibgib/core-gib/dist/cosmology/branching/commands/index.mjs";
|
|
95
|
+
import { validateBranchName } from "@ibgib/core-gib/dist/cosmology/branching/branch/branch-helpers.mjs";
|
|
96
|
+
|
|
97
|
+
export interface PanelLoadContext {
|
|
98
|
+
route: GalaxyRouteInfo;
|
|
99
|
+
cosmosName: string;
|
|
100
|
+
galaxyName: string;
|
|
101
|
+
discriminator?: string;
|
|
102
|
+
policy: GalaxyPolicy;
|
|
103
|
+
cosmosInfo?: CosmosInfo;
|
|
104
|
+
shell: SpaceGibShellService;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type PanelName = 'LeftPanel' | 'CenterPanel' | 'RightPanel';
|
|
108
|
+
|
|
109
|
+
export type PanelLoaderFn = (route: GalaxyRouteInfo, context: PanelLoadContext) => Promise<void>;
|
|
77
110
|
|
|
111
|
+
export type PanelLoaderMap = {
|
|
112
|
+
[K in PanelName as `loadRouteFor${K}`]: PanelLoaderFn;
|
|
113
|
+
};
|
|
78
114
|
|
|
79
115
|
export class SpaceGibShellService {
|
|
80
116
|
private lc: string = `[SpaceGibShellService]`;
|
|
81
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Default convention panel loaders for Branching Galaxies (Class I Substrate / Code).
|
|
120
|
+
*/
|
|
121
|
+
protected branchingPanelLoaders: PanelLoaderMap = {
|
|
122
|
+
loadRouteForLeftPanel: async (route, context) => {
|
|
123
|
+
this.expandActivityBar();
|
|
124
|
+
this.expandLeftPanel();
|
|
125
|
+
this.setActiveActivityBarButton('space', route.galaxy);
|
|
126
|
+
this.showLeftPanelView('code', route.galaxy);
|
|
127
|
+
if (this.fileExplorerInstance) {
|
|
128
|
+
this.fileExplorerInstance.setGalaxyAndBranch(route.galaxy, route.branch || 'main');
|
|
129
|
+
if (route.filePath) {
|
|
130
|
+
this.fileExplorerInstance.selectFile(route.filePath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (this.changesInstance) {
|
|
134
|
+
this.changesInstance.setGalaxyAndBranch(route.galaxy, route.branch || 'main', { preserveChanges: true });
|
|
135
|
+
}
|
|
136
|
+
if (this.codeEditorInstance) {
|
|
137
|
+
this.codeEditorInstance.setGalaxyAndBranch(route.galaxy, route.branch || 'main');
|
|
138
|
+
}
|
|
139
|
+
if (this.timelineInstance) {
|
|
140
|
+
this.timelineInstance.setBranch(route.branch || 'main');
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
loadRouteForCenterPanel: async (route, context) => {
|
|
144
|
+
this.switchToReposMode({ skipNavigate: true });
|
|
145
|
+
await this.showCode(route.filePath, route.branch, route.galaxy);
|
|
146
|
+
},
|
|
147
|
+
loadRouteForRightPanel: async (route, context) => {
|
|
148
|
+
if (route.query?.inspect) {
|
|
149
|
+
this.expandRightPanel();
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Default convention panel loaders for Linear Galaxies (Class IV Discourse / Notes).
|
|
156
|
+
*/
|
|
157
|
+
protected linearPanelLoaders: PanelLoaderMap = {
|
|
158
|
+
loadRouteForLeftPanel: async (route, context) => {
|
|
159
|
+
this.expandActivityBar();
|
|
160
|
+
this.expandLeftPanel();
|
|
161
|
+
this.setActiveActivityBarButton('space', route.galaxy);
|
|
162
|
+
this.showLeftPanelView('text', route.galaxy);
|
|
163
|
+
},
|
|
164
|
+
loadRouteForCenterPanel: async (route, context) => {
|
|
165
|
+
this.switchToNotesMode(route.topicTjp || route.galaxy, { skipNavigate: true, galaxyId: route.galaxy });
|
|
166
|
+
await this.showNotes(route.topicTjp || route.galaxy, {
|
|
167
|
+
trail: route.trail,
|
|
168
|
+
trailMode: route.trailMode,
|
|
169
|
+
query: route.query,
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
loadRouteForRightPanel: async (route, context) => {
|
|
173
|
+
if (route.query?.inspect) {
|
|
174
|
+
this.expandRightPanel();
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Registry of convention panel loaders keyed by topology or discriminator.
|
|
181
|
+
*/
|
|
182
|
+
protected panelLoaderRegistry: Record<string, PanelLoaderMap> = {
|
|
183
|
+
branching: this.branchingPanelLoaders,
|
|
184
|
+
linear: this.linearPanelLoaders,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
public registerPanelLoaders(key: string, loaders: PanelLoaderMap): void {
|
|
188
|
+
this.panelLoaderRegistry[key] = loaders;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public async loadRouteForPanels(route: GalaxyRouteInfo, context: PanelLoadContext): Promise<void> {
|
|
192
|
+
const loaders =
|
|
193
|
+
(context.discriminator ? this.panelLoaderRegistry[context.discriminator] : undefined) ||
|
|
194
|
+
this.panelLoaderRegistry[context.policy.topology] ||
|
|
195
|
+
this.branchingPanelLoaders;
|
|
196
|
+
|
|
197
|
+
await loaders.loadRouteForLeftPanel(route, context);
|
|
198
|
+
await loaders.loadRouteForCenterPanel(route, context);
|
|
199
|
+
await loaders.loadRouteForRightPanel(route, context);
|
|
200
|
+
}
|
|
201
|
+
|
|
82
202
|
public initialized: Promise<void>;
|
|
83
203
|
private isApplyingRoute: boolean = false;
|
|
84
204
|
private cosmosNavigatorInstance?: CosmosNavigatorComponentInstance;
|
|
85
205
|
private fileExplorerInstance?: FileExplorerComponentInstance;
|
|
206
|
+
private changesInstance?: ChangesComponentInstance;
|
|
86
207
|
private timelineInstance?: TimelineComponentInstance;
|
|
87
208
|
private timelineItemDetailsInstance?: TimelineItemDetailsComponentInstance;
|
|
88
209
|
private chatViewInstance?: ChatViewComponentInstance;
|
|
@@ -100,6 +221,8 @@ export class SpaceGibShellService {
|
|
|
100
221
|
private isResizingLeft = false;
|
|
101
222
|
private isResizingRight = false;
|
|
102
223
|
private isResizingFooter = false;
|
|
224
|
+
private isResizingExplorerChanges = false;
|
|
225
|
+
private isResizingChangesTimeline = false;
|
|
103
226
|
|
|
104
227
|
// Playground Banner State
|
|
105
228
|
private hasBigBangExploded = false;
|
|
@@ -114,6 +237,7 @@ export class SpaceGibShellService {
|
|
|
114
237
|
await this.registerComponents();
|
|
115
238
|
await this.initCosmosNavigator();
|
|
116
239
|
await this.initFileExplorer();
|
|
240
|
+
await this.initChanges();
|
|
117
241
|
await this.initTimeline();
|
|
118
242
|
await this.initChatView();
|
|
119
243
|
await this.initCodeEditor();
|
|
@@ -175,6 +299,44 @@ export class SpaceGibShellService {
|
|
|
175
299
|
footerResizer.addEventListener('mousedown', () => this.isResizingFooter = true);
|
|
176
300
|
}
|
|
177
301
|
|
|
302
|
+
// Accordion Horizontal Resizers (Left Panel)
|
|
303
|
+
const resizerExplorerChanges = document.getElementById('resizer-explorer-changes');
|
|
304
|
+
if (resizerExplorerChanges) {
|
|
305
|
+
resizerExplorerChanges.addEventListener('mousedown', (e) => {
|
|
306
|
+
e.preventDefault();
|
|
307
|
+
this.isResizingExplorerChanges = true;
|
|
308
|
+
resizerExplorerChanges.classList.add('active');
|
|
309
|
+
});
|
|
310
|
+
resizerExplorerChanges.addEventListener('dblclick', () => {
|
|
311
|
+
const explorerEl = document.getElementById('code-file-explorer-container');
|
|
312
|
+
if (explorerEl) {
|
|
313
|
+
explorerEl.style.flex = '';
|
|
314
|
+
explorerEl.style.height = '';
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const resizerChangesTimeline = document.getElementById('resizer-changes-timeline');
|
|
320
|
+
if (resizerChangesTimeline) {
|
|
321
|
+
resizerChangesTimeline.addEventListener('mousedown', (e) => {
|
|
322
|
+
e.preventDefault();
|
|
323
|
+
this.isResizingChangesTimeline = true;
|
|
324
|
+
resizerChangesTimeline.classList.add('active');
|
|
325
|
+
});
|
|
326
|
+
resizerChangesTimeline.addEventListener('dblclick', () => {
|
|
327
|
+
const changesEl = document.getElementById('code-changes-container');
|
|
328
|
+
const timelineEl = document.getElementById('code-timeline-container');
|
|
329
|
+
if (changesEl) {
|
|
330
|
+
changesEl.style.flex = '';
|
|
331
|
+
changesEl.style.height = '';
|
|
332
|
+
}
|
|
333
|
+
if (timelineEl) {
|
|
334
|
+
timelineEl.style.flex = '';
|
|
335
|
+
timelineEl.style.height = '';
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
178
340
|
// Window mouse events for dragging
|
|
179
341
|
window.addEventListener('mousemove', (e) => this.handleMouseMove(e));
|
|
180
342
|
window.addEventListener('mouseup', () => this.handleMouseUp());
|
|
@@ -437,7 +599,7 @@ export class SpaceGibShellService {
|
|
|
437
599
|
}
|
|
438
600
|
|
|
439
601
|
private handleMouseMove(e: MouseEvent) {
|
|
440
|
-
if (!this.isResizingLeft && !this.isResizingRight && !this.isResizingFooter) return;
|
|
602
|
+
if (!this.isResizingLeft && !this.isResizingRight && !this.isResizingFooter && !this.isResizingExplorerChanges && !this.isResizingChangesTimeline) return;
|
|
441
603
|
|
|
442
604
|
// Prevent text selection while dragging
|
|
443
605
|
e.preventDefault();
|
|
@@ -459,12 +621,40 @@ export class SpaceGibShellService {
|
|
|
459
621
|
let newHeight = Math.max(24, Math.min(window.innerHeight - e.clientY, 400));
|
|
460
622
|
document.documentElement.style.setProperty('--footer-panel-height', `${newHeight}px`);
|
|
461
623
|
}
|
|
624
|
+
|
|
625
|
+
if (this.isResizingExplorerChanges) {
|
|
626
|
+
const explorerEl = document.getElementById('code-file-explorer-container');
|
|
627
|
+
if (explorerEl) {
|
|
628
|
+
const rect = explorerEl.getBoundingClientRect();
|
|
629
|
+
const parentHeight = explorerEl.parentElement?.clientHeight || 600;
|
|
630
|
+
const maxExplorerHeight = parentHeight - 75;
|
|
631
|
+
const newHeight = Math.max(76, Math.min(e.clientY - rect.top, maxExplorerHeight));
|
|
632
|
+
explorerEl.style.flex = 'none';
|
|
633
|
+
explorerEl.style.height = `${newHeight}px`;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (this.isResizingChangesTimeline) {
|
|
638
|
+
const changesEl = document.getElementById('code-changes-container');
|
|
639
|
+
if (changesEl) {
|
|
640
|
+
const rect = changesEl.getBoundingClientRect();
|
|
641
|
+
const parentHeight = changesEl.parentElement?.clientHeight || 600;
|
|
642
|
+
const maxChangesHeight = parentHeight - (changesEl.offsetTop || 0) - 35;
|
|
643
|
+
const newHeight = Math.max(35, Math.min(e.clientY - rect.top, maxChangesHeight));
|
|
644
|
+
changesEl.style.flex = 'none';
|
|
645
|
+
changesEl.style.height = `${newHeight}px`;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
462
648
|
}
|
|
463
649
|
|
|
464
650
|
private handleMouseUp() {
|
|
465
651
|
this.isResizingLeft = false;
|
|
466
652
|
this.isResizingRight = false;
|
|
467
653
|
this.isResizingFooter = false;
|
|
654
|
+
this.isResizingExplorerChanges = false;
|
|
655
|
+
this.isResizingChangesTimeline = false;
|
|
656
|
+
document.getElementById('resizer-explorer-changes')?.classList.remove('active');
|
|
657
|
+
document.getElementById('resizer-changes-timeline')?.classList.remove('active');
|
|
468
658
|
}
|
|
469
659
|
|
|
470
660
|
private updateCssVariables() {
|
|
@@ -479,6 +669,7 @@ export class SpaceGibShellService {
|
|
|
479
669
|
await registerAdminReviewComponent();
|
|
480
670
|
await registerCosmosNavigatorComponent();
|
|
481
671
|
await registerFileExplorerComponent();
|
|
672
|
+
await registerChangesComponent();
|
|
482
673
|
await registerTimelineComponent();
|
|
483
674
|
await registerTimelineItemDetailsComponent();
|
|
484
675
|
await registerChatViewComponent();
|
|
@@ -560,6 +751,27 @@ export class SpaceGibShellService {
|
|
|
560
751
|
}
|
|
561
752
|
}
|
|
562
753
|
|
|
754
|
+
public show404(message: string): void {
|
|
755
|
+
const centerPanel = document.getElementById(ID_CENTER_PANEL_CONTENT);
|
|
756
|
+
if (centerPanel) {
|
|
757
|
+
centerPanel.innerHTML = `
|
|
758
|
+
<div class="cosmos-not-found-view" style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #94a3b8; text-align: center; padding: 2rem; font-family: sans-serif;">
|
|
759
|
+
<div style="font-size: 3.5rem; margin-bottom: 1rem;">🌌 404</div>
|
|
760
|
+
<h2 style="font-size: 1.5rem; color: #fff; margin-bottom: 0.5rem; font-weight: 600;">Cosmos Not Found</h2>
|
|
761
|
+
<p style="margin-bottom: 1.5rem; max-width: 420px; font-size: 0.95rem; line-height: 1.5;">${message}</p>
|
|
762
|
+
<button id="btn-404-return" type="button" style="padding: 10px 22px; border-radius: 8px; background: rgba(124, 92, 252, 0.2); border: 1px solid rgba(124, 92, 252, 0.4); color: #c4b5fd; cursor: pointer; font-weight: 500; font-size: 0.95rem; transition: background 0.2s;">
|
|
763
|
+
Return to Polycosmos
|
|
764
|
+
</button>
|
|
765
|
+
</div>
|
|
766
|
+
`;
|
|
767
|
+
const returnBtn = document.getElementById('btn-404-return');
|
|
768
|
+
returnBtn?.addEventListener('click', () => {
|
|
769
|
+
getSpaceGibRouterSvc().navigate({ kind: 'polycosmos' });
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
this.collapsePanels();
|
|
773
|
+
}
|
|
774
|
+
|
|
563
775
|
private async initFileExplorer(): Promise<void> {
|
|
564
776
|
const lc = `${this.lc}[${this.initFileExplorer.name}]`;
|
|
565
777
|
try {
|
|
@@ -594,49 +806,91 @@ export class SpaceGibShellService {
|
|
|
594
806
|
|
|
595
807
|
private bindFileExplorerEvents(): void {
|
|
596
808
|
window.addEventListener('space-gib-file-selected', (e: any) => {
|
|
597
|
-
const { branch, path, filename } = e.detail || {};
|
|
598
|
-
console.log(`${this.lc} File selected: ${path || filename} on worktree branch ${branch}`);
|
|
599
|
-
const fullFile = path || filename
|
|
809
|
+
const { branch, path, filename, galaxy } = e.detail || {};
|
|
810
|
+
console.log(`${this.lc} File selected: ${path || filename} on worktree branch ${branch} in galaxy ${galaxy}`);
|
|
811
|
+
const fullFile = path || filename;
|
|
812
|
+
if (!fullFile) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
600
815
|
const branchName = branch || 'main';
|
|
601
|
-
const
|
|
816
|
+
const galaxyName = galaxy || 'code-1';
|
|
817
|
+
const tipAddr = 'tip';
|
|
818
|
+
|
|
602
819
|
this.chatViewInstance?.setTargetFile(fullFile, `${branchName} @ ${tipAddr}`);
|
|
603
820
|
this.nestedChatInstance?.activateIbGib({ addr: `file ${fullFile}^${tipAddr}` });
|
|
604
821
|
|
|
605
|
-
|
|
606
|
-
if (fullFile === 'src/helper.ts') {
|
|
607
|
-
mockContent = `/**\n * @module my-app/helper\n * Utility functions for space-gib in-memory VCS.\n */\n\nexport function add(a: number, b: number): number {\n return a + b;\n}\n\nexport function multiply(a: number, b: number): number {\n return a * b;\n}\n`;
|
|
608
|
-
} else if (fullFile === 'README.md') {
|
|
609
|
-
mockContent = `# my-app\n\nDecentralized version-controlled application running on **space-gib**.\n\n- Zero SaaS lock-in\n- Inverted soft rel8ns for living companion discussions\n- Merkle DAG branch worktrees\n`;
|
|
610
|
-
} else if (fullFile === 'tsconfig.json') {
|
|
611
|
-
mockContent = `{\n "compilerOptions": {\n "target": "ES2022",\n "module": "NodeNext",\n "strict": true,\n "esModuleInterop": true\n }\n}\n`;
|
|
612
|
-
}
|
|
822
|
+
this.showCode(fullFile, branchName, galaxyName);
|
|
613
823
|
|
|
614
|
-
this.
|
|
615
|
-
|
|
616
|
-
|
|
824
|
+
const activeCosmos = this.cosmosNavigatorInstance?.getActiveCosmos();
|
|
825
|
+
if (activeCosmos) {
|
|
826
|
+
const tenant = this.getActiveTenant();
|
|
827
|
+
getSpaceGibRouterSvc().navigate({
|
|
828
|
+
kind: 'galaxy',
|
|
829
|
+
cosmos: activeCosmos.id || activeCosmos.name,
|
|
830
|
+
galaxy: galaxyName,
|
|
831
|
+
topology: 'branching',
|
|
832
|
+
discriminator: 'code',
|
|
617
833
|
branch: branchName,
|
|
618
|
-
|
|
619
|
-
|
|
834
|
+
filePath: fullFile,
|
|
835
|
+
...(tenant ? { tenant } : {}),
|
|
620
836
|
});
|
|
621
|
-
}
|
|
837
|
+
}
|
|
838
|
+
});
|
|
622
839
|
|
|
623
|
-
|
|
624
|
-
|
|
840
|
+
window.addEventListener('space-gib-branch-switched', async (e: any) => {
|
|
841
|
+
const { galaxy, branch } = e.detail || {};
|
|
842
|
+
const targetGalaxy = galaxy || this.fileExplorerInstance?.getGalaxyName() || 'code-1';
|
|
843
|
+
const targetBranch = branch || 'main';
|
|
844
|
+
|
|
845
|
+
console.log(`${this.lc} Branch switched: [${targetGalaxy}] -> [${targetBranch}]`);
|
|
846
|
+
|
|
847
|
+
// 1. Update File Explorer, Changes, Timeline, Code Editor
|
|
848
|
+
this.fileExplorerInstance?.setGalaxyAndBranch(targetGalaxy, targetBranch);
|
|
849
|
+
this.changesInstance?.setGalaxyAndBranch(targetGalaxy, targetBranch, { preserveChanges: true });
|
|
850
|
+
this.codeEditorInstance?.setGalaxyAndBranch(targetGalaxy, targetBranch);
|
|
851
|
+
this.timelineInstance?.setBranch(targetBranch);
|
|
852
|
+
|
|
853
|
+
// 2. Refresh active file under new branch context
|
|
854
|
+
const activePath = this.fileExplorerInstance?.getSelectedFilePath() || this.codeEditorInstance?.getFilepath();
|
|
855
|
+
if (activePath) {
|
|
856
|
+
await this.showCode(activePath, targetBranch, targetGalaxy);
|
|
857
|
+
} else {
|
|
858
|
+
await this.showCode(undefined, targetBranch, targetGalaxy);
|
|
859
|
+
}
|
|
625
860
|
|
|
861
|
+
// 3. Update router navigation
|
|
626
862
|
const activeCosmos = this.cosmosNavigatorInstance?.getActiveCosmos();
|
|
627
863
|
if (activeCosmos) {
|
|
628
|
-
const tenant = this.getActiveTenant();
|
|
864
|
+
const tenant = this.getActiveTenant(activeCosmos);
|
|
629
865
|
getSpaceGibRouterSvc().navigate({
|
|
630
|
-
kind: '
|
|
866
|
+
kind: 'galaxy',
|
|
631
867
|
cosmos: activeCosmos.id || activeCosmos.name,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
868
|
+
galaxy: targetGalaxy,
|
|
869
|
+
topology: 'branching',
|
|
870
|
+
discriminator: 'code',
|
|
871
|
+
branch: targetBranch,
|
|
872
|
+
...(activePath ? { filePath: activePath } : {}),
|
|
635
873
|
...(tenant ? { tenant } : {}),
|
|
636
874
|
});
|
|
637
875
|
}
|
|
638
876
|
});
|
|
639
877
|
|
|
878
|
+
window.addEventListener('space-gib-view-mode-changed', (e: any) => {
|
|
879
|
+
const { mode } = e.detail || {};
|
|
880
|
+
if (mode) {
|
|
881
|
+
this.changesInstance?.setViewMode(mode);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
window.addEventListener('space-gib-accordion-toggled', () => {
|
|
886
|
+
const explorerEl = document.getElementById('code-file-explorer-container');
|
|
887
|
+
const changesEl = document.getElementById('code-changes-container');
|
|
888
|
+
const timelineEl = document.getElementById('code-timeline-container');
|
|
889
|
+
if (explorerEl) { explorerEl.style.flex = ''; explorerEl.style.height = ''; }
|
|
890
|
+
if (changesEl) { changesEl.style.flex = ''; changesEl.style.height = ''; }
|
|
891
|
+
if (timelineEl) { timelineEl.style.flex = ''; timelineEl.style.height = ''; }
|
|
892
|
+
});
|
|
893
|
+
|
|
640
894
|
window.addEventListener('space-gib-new-file-requested', (e: any) => {
|
|
641
895
|
const { branch } = e.detail || {};
|
|
642
896
|
const filename = prompt(`Create new file on branch [${branch || 'main'}]:`, 'untitled.ts');
|
|
@@ -654,6 +908,117 @@ export class SpaceGibShellService {
|
|
|
654
908
|
});
|
|
655
909
|
}
|
|
656
910
|
|
|
911
|
+
private async initChanges(): Promise<void> {
|
|
912
|
+
const lc = `${this.lc}[${this.initChanges.name}]`;
|
|
913
|
+
try {
|
|
914
|
+
const container = document.getElementById('code-changes-container');
|
|
915
|
+
if (!container) {
|
|
916
|
+
console.warn(`${lc} code-changes-container element not found.`);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const componentSvc = await getComponentSvc();
|
|
921
|
+
this.changesInstance = await componentSvc.getComponentInstance({
|
|
922
|
+
path: CHANGES_COMPONENT_NAME,
|
|
923
|
+
ibGibAddr: ROOT_ADDR,
|
|
924
|
+
useRegExpPrefilter: true,
|
|
925
|
+
}) as ChangesComponentInstance;
|
|
926
|
+
|
|
927
|
+
if (!this.changesInstance) {
|
|
928
|
+
throw new Error(`Failed to instantiate ${CHANGES_COMPONENT_NAME}`);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
await componentSvc.inject({
|
|
932
|
+
parentEl: container,
|
|
933
|
+
componentToInject: this.changesInstance,
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
if (this.fileExplorerInstance) {
|
|
937
|
+
this.changesInstance.setViewMode(this.fileExplorerInstance.getViewMode());
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
this.bindChangesEvents();
|
|
941
|
+
|
|
942
|
+
} catch (error) {
|
|
943
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
private bindChangesEvents(): void {
|
|
948
|
+
window.addEventListener('space-gib-commit-created', (e: any) => {
|
|
949
|
+
const { branch, message, tipAddr, shortHash } = e.detail || {};
|
|
950
|
+
console.log(`${this.lc} Commit created: [${shortHash}] "${message}" on branch [${branch}]`);
|
|
951
|
+
|
|
952
|
+
// 1. Clear status badges in file explorer for this branch
|
|
953
|
+
this.fileExplorerInstance?.clearAllStatusBadges(branch);
|
|
954
|
+
this.fileExplorerInstance?.updateDirtyBadges();
|
|
955
|
+
|
|
956
|
+
// 2. Add snapshot to timeline
|
|
957
|
+
this.timelineInstance?.addSnapshot({
|
|
958
|
+
hash: tipAddr,
|
|
959
|
+
shortHash: shortHash || (tipAddr ? tipAddr.slice(-8) : 'unknown'),
|
|
960
|
+
message: message || 'Update',
|
|
961
|
+
author: 'You',
|
|
962
|
+
timestamp: 'Just now',
|
|
963
|
+
branch: branch || 'main',
|
|
964
|
+
isTip: true,
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
// 3. Update breadcrumb tip and mark committed in code editor
|
|
968
|
+
if (this.codeEditorInstance) {
|
|
969
|
+
if (shortHash) {
|
|
970
|
+
this.codeEditorInstance.setTipAddr(shortHash);
|
|
971
|
+
}
|
|
972
|
+
const activePath = this.codeEditorInstance.getFilepath();
|
|
973
|
+
if (activePath) {
|
|
974
|
+
this.codeEditorInstance.markAsCommitted(shortHash || tipAddr);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
window.addEventListener('space-gib-file-created', (e: any) => {
|
|
980
|
+
const { path, content, galaxy, branch } = e.detail || {};
|
|
981
|
+
if (galaxy || branch) {
|
|
982
|
+
const g = galaxy || this.changesInstance?.getGalaxyName() || 'code-1';
|
|
983
|
+
const b = branch || this.changesInstance?.getBranchName() || 'main';
|
|
984
|
+
this.changesInstance?.setGalaxyAndBranch(g, b, { preserveChanges: true });
|
|
985
|
+
this.codeEditorInstance?.setGalaxyAndBranch(g, b);
|
|
986
|
+
}
|
|
987
|
+
if (path) {
|
|
988
|
+
this.changesInstance?.recordChange({
|
|
989
|
+
path,
|
|
990
|
+
status: 'untracked',
|
|
991
|
+
content: content ?? '',
|
|
992
|
+
});
|
|
993
|
+
this.fileExplorerInstance?.updateDirtyBadges();
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
window.addEventListener('space-gib-change-discarded', (e: any) => {
|
|
998
|
+
const { path, originalContent, branch, galaxy } = e.detail || {};
|
|
999
|
+
if (path) {
|
|
1000
|
+
const b = branch || this.fileExplorerInstance?.getBranchName() || 'main';
|
|
1001
|
+
const g = galaxy || this.fileExplorerInstance?.getGalaxyName() || 'code-1';
|
|
1002
|
+
if (this.fileExplorerInstance?.isUntracked(path, b, g)) {
|
|
1003
|
+
this.fileExplorerInstance.removeFile(path, b, g);
|
|
1004
|
+
if (this.codeEditorInstance && this.codeEditorInstance.getFilepath() === path) {
|
|
1005
|
+
this.codeEditorInstance.clearFile({ repo: g, branch: b });
|
|
1006
|
+
}
|
|
1007
|
+
} else {
|
|
1008
|
+
this.fileExplorerInstance?.setFileStatus(path, undefined, b, g);
|
|
1009
|
+
if (this.codeEditorInstance && this.codeEditorInstance.getFilepath() === path) {
|
|
1010
|
+
if (originalContent !== undefined) {
|
|
1011
|
+
this.codeEditorInstance.setContent(originalContent);
|
|
1012
|
+
} else {
|
|
1013
|
+
this.showCode(path, b, g);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
this.fileExplorerInstance?.updateDirtyBadges();
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
|
|
657
1022
|
private async initTimeline(): Promise<void> {
|
|
658
1023
|
const lc = `${this.lc}[${this.initTimeline.name}]`;
|
|
659
1024
|
try {
|
|
@@ -781,7 +1146,7 @@ export class SpaceGibShellService {
|
|
|
781
1146
|
}
|
|
782
1147
|
}
|
|
783
1148
|
|
|
784
|
-
public async showCode(filePath?: string, branch?: string): Promise<void> {
|
|
1149
|
+
public async showCode(filePath?: string, branch?: string, galaxy?: string): Promise<void> {
|
|
785
1150
|
const lc = `${this.lc}[${this.showCode.name}]`;
|
|
786
1151
|
try {
|
|
787
1152
|
const centerPanel = document.getElementById(ID_CENTER_PANEL_CONTENT);
|
|
@@ -790,6 +1155,10 @@ export class SpaceGibShellService {
|
|
|
790
1155
|
return;
|
|
791
1156
|
}
|
|
792
1157
|
|
|
1158
|
+
const currentRoute = getSpaceGibRouterSvc().getCurrentRoute();
|
|
1159
|
+
const targetGalaxy = galaxy || (currentRoute && 'galaxy' in currentRoute ? (currentRoute as any).galaxy : undefined) || this.fileExplorerInstance?.getGalaxyName() || this.changesInstance?.getGalaxyName() || 'code-1';
|
|
1160
|
+
const targetBranch = branch || (currentRoute && 'branch' in currentRoute ? (currentRoute as any).branch : undefined) || this.fileExplorerInstance?.getBranchName() || this.changesInstance?.getBranchName() || 'main';
|
|
1161
|
+
|
|
793
1162
|
if (!this.codeEditorInstance) {
|
|
794
1163
|
const componentSvc = await getComponentSvc();
|
|
795
1164
|
this.codeEditorInstance = await componentSvc.getComponentInstance({
|
|
@@ -806,25 +1175,81 @@ export class SpaceGibShellService {
|
|
|
806
1175
|
componentToInject: this.codeEditorInstance,
|
|
807
1176
|
});
|
|
808
1177
|
|
|
1178
|
+
this.codeEditorInstance.setGalaxyAndBranch(targetGalaxy, targetBranch);
|
|
1179
|
+
|
|
809
1180
|
if (filePath) {
|
|
810
|
-
let
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1181
|
+
let casContent: string | undefined = undefined;
|
|
1182
|
+
let tipAddr: string = 'tip';
|
|
1183
|
+
|
|
1184
|
+
try {
|
|
1185
|
+
const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
|
|
1186
|
+
const router = getSpaceGibRouterSvc();
|
|
1187
|
+
let galaxyIbGib: B2tFSGalaxyIbGib_V1 | undefined;
|
|
1188
|
+
for (const manifest of router.cosmosManifestCache?.values() || []) {
|
|
1189
|
+
const entry = manifest.data?.galaxies?.[targetGalaxy];
|
|
1190
|
+
if (entry?.galaxyAddr) {
|
|
1191
|
+
galaxyIbGib = await getIbGibFromSpace<B2tFSGalaxyIbGib_V1>({ addr: entry.galaxyAddr, space });
|
|
1192
|
+
if (galaxyIbGib) break;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (galaxyIbGib) {
|
|
1196
|
+
const branchAndRoot = await getBranchAndRootItemInfosAndIbGibsAndSpaceFromGalaxyIbGib({
|
|
1197
|
+
galaxyIbGib,
|
|
1198
|
+
branchName: targetBranch,
|
|
1199
|
+
metaspace,
|
|
1200
|
+
});
|
|
1201
|
+
tipAddr = branchAndRoot.branchIbGib.gib || 'tip';
|
|
1202
|
+
const rootItem = branchAndRoot.rootItemIbGib_latest || branchAndRoot.rootItemIbGib;
|
|
1203
|
+
const fileItem = await getFileItemFromPath({
|
|
1204
|
+
branchSpace: branchAndRoot.branchSpace,
|
|
1205
|
+
rootItem,
|
|
1206
|
+
filePath,
|
|
1207
|
+
});
|
|
1208
|
+
if (fileItem) {
|
|
1209
|
+
casContent = await getFileContent({ branchSpace: branchAndRoot.branchSpace, fileItem });
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
} catch (readErr) {
|
|
1213
|
+
console.warn(`${lc} Error reading file [${filePath}] from branch space: ${extractErrorMsg(readErr)}`);
|
|
817
1214
|
}
|
|
818
1215
|
|
|
1216
|
+
const workingChange = this.changesInstance?.getChange(filePath, targetBranch);
|
|
1217
|
+
const isUntrackedInExplorer = this.fileExplorerInstance?.isUntracked(filePath, targetBranch, targetGalaxy);
|
|
1218
|
+
const fileExistsInCas = casContent !== undefined;
|
|
1219
|
+
const hasWorkingTreeChange = workingChange !== undefined;
|
|
1220
|
+
|
|
1221
|
+
// If file doesn't exist in CAS, and is neither in working tree nor marked untracked in explorer, clear editor
|
|
1222
|
+
if (!fileExistsInCas && !hasWorkingTreeChange && !isUntrackedInExplorer) {
|
|
1223
|
+
this.codeEditorInstance.clearFile({
|
|
1224
|
+
repo: targetGalaxy,
|
|
1225
|
+
branch: targetBranch,
|
|
1226
|
+
});
|
|
1227
|
+
this.fileExplorerInstance?.selectFile('');
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
const isUntracked = !fileExistsInCas;
|
|
1232
|
+
const content = workingChange?.content ?? casContent ?? '';
|
|
1233
|
+
|
|
819
1234
|
this.codeEditorInstance.loadFile({
|
|
820
1235
|
filepath: filePath,
|
|
821
|
-
|
|
822
|
-
|
|
1236
|
+
repo: targetGalaxy,
|
|
1237
|
+
branch: targetBranch,
|
|
1238
|
+
tipAddr,
|
|
823
1239
|
content,
|
|
1240
|
+
originalContent: casContent,
|
|
1241
|
+
isUntracked,
|
|
1242
|
+
});
|
|
1243
|
+
} else {
|
|
1244
|
+
this.codeEditorInstance.clearFile({
|
|
1245
|
+
repo: targetGalaxy,
|
|
1246
|
+
branch: targetBranch,
|
|
824
1247
|
});
|
|
825
1248
|
}
|
|
826
1249
|
}
|
|
827
1250
|
|
|
1251
|
+
this.changesInstance?.setGalaxyAndBranch(targetGalaxy, targetBranch, { preserveChanges: true });
|
|
1252
|
+
|
|
828
1253
|
const codeChatContainer = document.getElementById('code-chat-view-container');
|
|
829
1254
|
const notesInspectorContainer = document.getElementById('notes-inspector-container');
|
|
830
1255
|
if (notesInspectorContainer) { notesInspectorContainer.style.display = 'none'; }
|
|
@@ -1004,8 +1429,25 @@ export class SpaceGibShellService {
|
|
|
1004
1429
|
|
|
1005
1430
|
private bindCodeEditorEvents(): void {
|
|
1006
1431
|
window.addEventListener('space-gib-code-changed', (e: any) => {
|
|
1007
|
-
const { filepath, lineCount } = e.detail || {};
|
|
1008
|
-
|
|
1432
|
+
const { filepath, content, lineCount, isReverted, isUntracked: isUntrackedProp, branch, repo } = e.detail || {};
|
|
1433
|
+
const targetBranch = branch || this.changesInstance?.getBranchName() || 'main';
|
|
1434
|
+
const targetGalaxy = repo || this.changesInstance?.getGalaxyName() || 'code-1';
|
|
1435
|
+
console.log(`${this.lc} Code changed in ${filepath} on branch [${targetBranch}] (${lineCount} lines, isReverted=${isReverted})`);
|
|
1436
|
+
if (filepath) {
|
|
1437
|
+
if (isReverted) {
|
|
1438
|
+
this.changesInstance?.removeChange(filepath, targetBranch);
|
|
1439
|
+
this.fileExplorerInstance?.setFileStatus(filepath, undefined, targetBranch, targetGalaxy);
|
|
1440
|
+
} else {
|
|
1441
|
+
const isUntracked = Boolean(isUntrackedProp || this.changesInstance?.isUntracked(filepath, targetBranch) || this.fileExplorerInstance?.isUntracked(filepath, targetBranch, targetGalaxy));
|
|
1442
|
+
const status = isUntracked ? 'untracked' : 'modified';
|
|
1443
|
+
this.changesInstance?.recordChange({
|
|
1444
|
+
path: filepath,
|
|
1445
|
+
status,
|
|
1446
|
+
content: content ?? '',
|
|
1447
|
+
}, targetBranch);
|
|
1448
|
+
this.fileExplorerInstance?.setFileStatus(filepath, status, targetBranch, targetGalaxy);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1009
1451
|
});
|
|
1010
1452
|
|
|
1011
1453
|
window.addEventListener('space-gib-code-copied', (e: any) => {
|
|
@@ -1165,8 +1607,7 @@ export class SpaceGibShellService {
|
|
|
1165
1607
|
if (activitySpaces) {
|
|
1166
1608
|
let matched = false;
|
|
1167
1609
|
activitySpaces.querySelectorAll('.activity-bar-btn').forEach(b => {
|
|
1168
|
-
const isMatch = b.getAttribute('data-space-id') === spaceId
|
|
1169
|
-
b.getAttribute('data-space-type') === spaceId;
|
|
1610
|
+
const isMatch = b.getAttribute('data-space-id') === spaceId;
|
|
1170
1611
|
b.classList.toggle('active', isMatch);
|
|
1171
1612
|
if (isMatch) matched = true;
|
|
1172
1613
|
});
|
|
@@ -1269,10 +1710,33 @@ export class SpaceGibShellService {
|
|
|
1269
1710
|
}
|
|
1270
1711
|
if (space.type === 'code') {
|
|
1271
1712
|
this.showLeftPanelView('code', space.name);
|
|
1272
|
-
this.switchToReposMode();
|
|
1713
|
+
this.switchToReposMode({ skipNavigate: true, galaxyId: space.name });
|
|
1714
|
+
if (!this.isApplyingRoute && cosmos?.name) {
|
|
1715
|
+
const tenant = this.getActiveTenant(cosmos.name);
|
|
1716
|
+
getSpaceGibRouterSvc().navigate({
|
|
1717
|
+
kind: 'galaxy',
|
|
1718
|
+
...(tenant ? { tenant } : {}),
|
|
1719
|
+
cosmos: cosmos.name,
|
|
1720
|
+
galaxy: space.name,
|
|
1721
|
+
topology: 'branching',
|
|
1722
|
+
discriminator: 'code',
|
|
1723
|
+
branch: 'main',
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1273
1726
|
} else if (space.type === 'text') {
|
|
1274
1727
|
this.showLeftPanelView('text', space.name);
|
|
1275
|
-
this.switchToNotesMode(space.name);
|
|
1728
|
+
this.switchToNotesMode(space.name, { skipNavigate: true, galaxyId: space.name });
|
|
1729
|
+
if (!this.isApplyingRoute && cosmos?.name) {
|
|
1730
|
+
const tenant = this.getActiveTenant(cosmos.name);
|
|
1731
|
+
getSpaceGibRouterSvc().navigate({
|
|
1732
|
+
kind: 'galaxy',
|
|
1733
|
+
...(tenant ? { tenant } : {}),
|
|
1734
|
+
cosmos: cosmos.name,
|
|
1735
|
+
galaxy: space.name,
|
|
1736
|
+
topology: 'linear',
|
|
1737
|
+
discriminator: 'notes',
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1276
1740
|
}
|
|
1277
1741
|
}
|
|
1278
1742
|
});
|
|
@@ -1315,12 +1779,100 @@ export class SpaceGibShellService {
|
|
|
1315
1779
|
this.openCloneModal(e.detail);
|
|
1316
1780
|
});
|
|
1317
1781
|
|
|
1318
|
-
window.addEventListener('space-gib-branch-requested', (e: any) => {
|
|
1782
|
+
window.addEventListener('space-gib-branch-requested', async (e: any) => {
|
|
1319
1783
|
const { galaxyName, sourceBranch, newBranchName, scope, itemPath } = e.detail || {};
|
|
1320
|
-
const
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1784
|
+
const cleanGalaxy = galaxyName || 'code-1';
|
|
1785
|
+
const cleanSourceBranch = sourceBranch || 'main';
|
|
1786
|
+
const cleanNewBranch = newBranchName?.trim();
|
|
1787
|
+
if (!cleanNewBranch) return;
|
|
1788
|
+
|
|
1789
|
+
const validation = validateBranchName(cleanNewBranch);
|
|
1790
|
+
if (!validation.isValid) {
|
|
1791
|
+
alert(`Invalid branch name: ${validation.error}`);
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
const lc = `${this.lc}[space-gib-branch-requested]`;
|
|
1796
|
+
try {
|
|
1797
|
+
const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
|
|
1798
|
+
const router = getSpaceGibRouterSvc();
|
|
1799
|
+
|
|
1800
|
+
// 1. Resolve GalaxyIbGib
|
|
1801
|
+
let galaxyIbGib: B2tFSGalaxyIbGib_V1 | undefined;
|
|
1802
|
+
for (const manifest of router.cosmosManifestCache?.values() || []) {
|
|
1803
|
+
const entry = manifest.data?.galaxies?.[cleanGalaxy];
|
|
1804
|
+
if (entry?.galaxyAddr) {
|
|
1805
|
+
galaxyIbGib = await getIbGibFromSpace<B2tFSGalaxyIbGib_V1>({ addr: entry.galaxyAddr, space });
|
|
1806
|
+
if (galaxyIbGib) break;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
if (!galaxyIbGib) {
|
|
1811
|
+
throw new Error(`Galaxy [${cleanGalaxy}] not found in cosmos manifest.`);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
// 2. Resolve source branch space
|
|
1815
|
+
const branchAndRoot = await getBranchAndRootItemInfosAndIbGibsAndSpaceFromGalaxyIbGib({
|
|
1816
|
+
galaxyIbGib,
|
|
1817
|
+
branchName: cleanSourceBranch,
|
|
1818
|
+
metaspace,
|
|
1819
|
+
});
|
|
1820
|
+
|
|
1821
|
+
const activeBranchSpace = branchAndRoot.branchSpace;
|
|
1822
|
+
|
|
1823
|
+
// 3. Execute isomorphic VCS branch creation
|
|
1824
|
+
const branchRes = await executeVcsBranch({
|
|
1825
|
+
metaspace,
|
|
1826
|
+
localSpace: space,
|
|
1827
|
+
sourceBranchSpace: activeBranchSpace,
|
|
1828
|
+
galaxyIbGib,
|
|
1829
|
+
branchName: cleanNewBranch,
|
|
1830
|
+
sourceBranchName: cleanSourceBranch,
|
|
1831
|
+
itemPath: scope === 'item' ? itemPath : undefined,
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
const finalGalaxy = branchRes.updatedGalaxy || galaxyIbGib;
|
|
1835
|
+
const finalGalaxyAddr = getIbGibAddr({ ibGib: finalGalaxy });
|
|
1836
|
+
|
|
1837
|
+
// 4. Update router cosmos manifest cache with updated galaxy address
|
|
1838
|
+
for (const manifest of router.cosmosManifestCache?.values() || []) {
|
|
1839
|
+
if (manifest.data?.galaxies?.[cleanGalaxy]) {
|
|
1840
|
+
manifest.data.galaxies[cleanGalaxy].galaxyAddr = finalGalaxyAddr;
|
|
1841
|
+
break;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
// 5. Broadcast new galaxy IbGib to metaspace subscribers
|
|
1846
|
+
await (metaspace as any).registerNewIbGib?.({ ibGib: finalGalaxy, space });
|
|
1847
|
+
|
|
1848
|
+
// 6. Update Changes, File Explorer & Code Editor
|
|
1849
|
+
this.changesInstance?.setGalaxyAndBranch(cleanGalaxy, cleanNewBranch);
|
|
1850
|
+
this.fileExplorerInstance?.setGalaxyAndBranch(cleanGalaxy, cleanNewBranch);
|
|
1851
|
+
this.codeEditorInstance?.setGalaxyAndBranch(cleanGalaxy, cleanNewBranch);
|
|
1852
|
+
this.timelineInstance?.setBranch(cleanNewBranch);
|
|
1853
|
+
|
|
1854
|
+
// 8. Navigate router to new branch
|
|
1855
|
+
const activeCosmos = this.cosmosNavigatorInstance?.getActiveCosmos();
|
|
1856
|
+
const activePath = this.codeEditorInstance?.getFilepath();
|
|
1857
|
+
if (activeCosmos) {
|
|
1858
|
+
const tenant = this.getActiveTenant(activeCosmos);
|
|
1859
|
+
router.navigate({
|
|
1860
|
+
kind: 'galaxy',
|
|
1861
|
+
cosmos: activeCosmos.id || activeCosmos.name,
|
|
1862
|
+
galaxy: cleanGalaxy,
|
|
1863
|
+
topology: 'branching',
|
|
1864
|
+
discriminator: 'code',
|
|
1865
|
+
branch: cleanNewBranch,
|
|
1866
|
+
...(activePath ? { filePath: activePath } : {}),
|
|
1867
|
+
...(tenant ? { tenant } : {}),
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
console.log(`${lc} Successfully diverged to new branch [${cleanNewBranch}] from ${scope === 'item' ? `item [${itemPath}]` : `worktree [${cleanSourceBranch}]`} in galaxy [${cleanGalaxy}]`);
|
|
1872
|
+
} catch (err) {
|
|
1873
|
+
console.error(`${lc} Failed to branch: ${extractErrorMsg(err)}`);
|
|
1874
|
+
alert(`Failed to create branch: ${extractErrorMsg(err)}`);
|
|
1875
|
+
}
|
|
1324
1876
|
});
|
|
1325
1877
|
|
|
1326
1878
|
btnFooterAgent?.addEventListener('click', () => {
|
|
@@ -1413,9 +1965,9 @@ export class SpaceGibShellService {
|
|
|
1413
1965
|
|
|
1414
1966
|
btnSideNewCosmos?.addEventListener('click', () => {
|
|
1415
1967
|
this.switchToSpacesMode();
|
|
1416
|
-
this.cosmosNavigatorInstance?.triggerBigBangSequence(() => {
|
|
1968
|
+
this.cosmosNavigatorInstance?.triggerBigBangSequence(async () => {
|
|
1417
1969
|
const nextIdx = (this.cosmosNavigatorInstance?.getCosmoses().length || 0) + 1;
|
|
1418
|
-
const newCosmos = this.cosmosNavigatorInstance?.createCosmos(`
|
|
1970
|
+
const newCosmos = await this.cosmosNavigatorInstance?.createCosmos(`cosmos-${nextIdx}`);
|
|
1419
1971
|
if (newCosmos) {
|
|
1420
1972
|
this.cosmosNavigatorInstance?.selectCosmos(newCosmos.id);
|
|
1421
1973
|
}
|
|
@@ -1461,13 +2013,14 @@ export class SpaceGibShellService {
|
|
|
1461
2013
|
spacesList.querySelectorAll('.cosmos-space-item').forEach(el => {
|
|
1462
2014
|
el.addEventListener('click', () => {
|
|
1463
2015
|
const type = el.getAttribute('data-space-type');
|
|
2016
|
+
const spaceId = el.getAttribute('data-space-id') || '';
|
|
1464
2017
|
const name = el.querySelector('.space-item-name')?.textContent || '';
|
|
1465
2018
|
if (type === 'code') {
|
|
1466
2019
|
this.showLeftPanelView('code', name);
|
|
1467
|
-
this.switchToReposMode();
|
|
2020
|
+
this.switchToReposMode({ galaxyId: spaceId });
|
|
1468
2021
|
} else {
|
|
1469
2022
|
this.showLeftPanelView('text', name);
|
|
1470
|
-
this.switchToNotesMode(name);
|
|
2023
|
+
this.switchToNotesMode(name, { galaxyId: spaceId });
|
|
1471
2024
|
}
|
|
1472
2025
|
});
|
|
1473
2026
|
});
|
|
@@ -1492,10 +2045,10 @@ export class SpaceGibShellService {
|
|
|
1492
2045
|
|
|
1493
2046
|
if (type === 'code') {
|
|
1494
2047
|
this.showLeftPanelView('code', title);
|
|
1495
|
-
this.switchToReposMode();
|
|
2048
|
+
this.switchToReposMode({ galaxyId: spaceId });
|
|
1496
2049
|
} else {
|
|
1497
2050
|
this.showLeftPanelView('text', title);
|
|
1498
|
-
this.switchToNotesMode(title);
|
|
2051
|
+
this.switchToNotesMode(title, { galaxyId: spaceId });
|
|
1499
2052
|
}
|
|
1500
2053
|
});
|
|
1501
2054
|
});
|
|
@@ -1603,12 +2156,12 @@ export class SpaceGibShellService {
|
|
|
1603
2156
|
});
|
|
1604
2157
|
|
|
1605
2158
|
const btnNew = menu.querySelector('#btn-header-menu-new-cosmos');
|
|
1606
|
-
btnNew?.addEventListener('click', () => {
|
|
2159
|
+
btnNew?.addEventListener('click', async () => {
|
|
1607
2160
|
menu.classList.add('hidden');
|
|
1608
2161
|
this.switchToSpacesMode();
|
|
1609
2162
|
this.cosmosNavigatorInstance?.triggerBigBangExplosion();
|
|
1610
2163
|
const nextIdx = cosmoses.length + 1;
|
|
1611
|
-
const newC = this.cosmosNavigatorInstance?.createCosmos(`
|
|
2164
|
+
const newC = await this.cosmosNavigatorInstance?.createCosmos(`cosmos-${nextIdx}`);
|
|
1612
2165
|
if (newC) {
|
|
1613
2166
|
setTimeout(() => {
|
|
1614
2167
|
this.cosmosNavigatorInstance?.selectCosmos(newC.id);
|
|
@@ -1623,17 +2176,25 @@ export class SpaceGibShellService {
|
|
|
1623
2176
|
const viewCode = document.getElementById('left-panel-code-view');
|
|
1624
2177
|
const viewText = document.getElementById('left-panel-text-view');
|
|
1625
2178
|
|
|
1626
|
-
if (viewPoly) {
|
|
1627
|
-
|
|
2179
|
+
if (viewPoly) {
|
|
2180
|
+
viewPoly.style.display = viewName === 'polycosmos' ? 'flex' : 'none';
|
|
2181
|
+
viewPoly.style.flexDirection = 'column';
|
|
2182
|
+
}
|
|
2183
|
+
if (viewCosmos) {
|
|
2184
|
+
viewCosmos.style.display = viewName === 'cosmos' ? 'flex' : 'none';
|
|
2185
|
+
viewCosmos.style.flexDirection = 'column';
|
|
2186
|
+
}
|
|
1628
2187
|
if (viewCode) {
|
|
1629
|
-
viewCode.style.display = viewName === 'code' ? '
|
|
2188
|
+
viewCode.style.display = viewName === 'code' ? 'flex' : 'none';
|
|
2189
|
+
viewCode.style.flexDirection = 'column';
|
|
1630
2190
|
if (title) {
|
|
1631
2191
|
const titleEl = document.getElementById('left-code-space-title');
|
|
1632
2192
|
if (titleEl) { titleEl.textContent = title; }
|
|
1633
2193
|
}
|
|
1634
2194
|
}
|
|
1635
2195
|
if (viewText) {
|
|
1636
|
-
viewText.style.display = viewName === 'text' ? '
|
|
2196
|
+
viewText.style.display = viewName === 'text' ? 'flex' : 'none';
|
|
2197
|
+
viewText.style.flexDirection = 'column';
|
|
1637
2198
|
if (viewName === 'text') {
|
|
1638
2199
|
this.initNotesExplorer(title);
|
|
1639
2200
|
}
|
|
@@ -1668,7 +2229,7 @@ export class SpaceGibShellService {
|
|
|
1668
2229
|
this.setMode('spaces');
|
|
1669
2230
|
}
|
|
1670
2231
|
|
|
1671
|
-
private switchToReposMode(opts?: { skipNavigate?: boolean }): void {
|
|
2232
|
+
private switchToReposMode(opts?: { skipNavigate?: boolean; galaxyId?: string }): void {
|
|
1672
2233
|
this.setMode('repos');
|
|
1673
2234
|
this.expandRightPanel();
|
|
1674
2235
|
if (!opts?.skipNavigate && !this.isApplyingRoute) {
|
|
@@ -1676,9 +2237,11 @@ export class SpaceGibShellService {
|
|
|
1676
2237
|
if (activeCosmos) {
|
|
1677
2238
|
const tenant = this.getActiveTenant(activeCosmos);
|
|
1678
2239
|
getSpaceGibRouterSvc().navigate({
|
|
1679
|
-
kind: '
|
|
2240
|
+
kind: 'galaxy',
|
|
1680
2241
|
cosmos: activeCosmos.id || activeCosmos.name,
|
|
1681
|
-
|
|
2242
|
+
galaxy: opts?.galaxyId || 'code-1',
|
|
2243
|
+
topology: 'branching',
|
|
2244
|
+
discriminator: 'code',
|
|
1682
2245
|
branch: 'main',
|
|
1683
2246
|
...(tenant ? { tenant } : {}),
|
|
1684
2247
|
});
|
|
@@ -1694,10 +2257,12 @@ export class SpaceGibShellService {
|
|
|
1694
2257
|
if (activeCosmos) {
|
|
1695
2258
|
const tenant = this.getActiveTenant(activeCosmos);
|
|
1696
2259
|
getSpaceGibRouterSvc().navigate({
|
|
1697
|
-
kind: '
|
|
2260
|
+
kind: 'galaxy',
|
|
1698
2261
|
cosmos: activeCosmos.id || activeCosmos.name,
|
|
1699
|
-
|
|
1700
|
-
|
|
2262
|
+
galaxy: opts?.galaxyId || 'notes-1',
|
|
2263
|
+
topology: 'linear',
|
|
2264
|
+
discriminator: 'notes',
|
|
2265
|
+
...(title ? { topicTjp: title, trail: [title], trailMode: 'tjp' } : {}),
|
|
1701
2266
|
...(tenant ? { tenant } : {}),
|
|
1702
2267
|
});
|
|
1703
2268
|
}
|
|
@@ -1745,12 +2310,17 @@ export class SpaceGibShellService {
|
|
|
1745
2310
|
try {
|
|
1746
2311
|
if (route.kind !== 'polycosmos') {
|
|
1747
2312
|
this.hasBigBangExploded = true;
|
|
2313
|
+
if (this.cosmosNavigatorInstance) {
|
|
2314
|
+
this.cosmosNavigatorInstance.hasBigBangExploded = true;
|
|
2315
|
+
}
|
|
1748
2316
|
this.revealChrome();
|
|
1749
2317
|
}
|
|
1750
2318
|
|
|
1751
2319
|
// If the route omitted a tenant specifier but the user is authenticated (or in playground),
|
|
1752
2320
|
// canonicalize the URL in the address bar so copying and sharing is always fully qualified.
|
|
1753
|
-
|
|
2321
|
+
// Exception: For bare landing ('polycosmos'), do not attach tenant or redirect to /@playground/polycosmos
|
|
2322
|
+
// so the URL remains bare (e.g. https://local.ibgib.space) to keep full focus on Big Bang.
|
|
2323
|
+
if (route.kind !== 'admin-review' && route.kind !== 'polycosmos' && !route.tenant) {
|
|
1754
2324
|
const cosmosName = 'cosmos' in route ? route.cosmos : undefined;
|
|
1755
2325
|
const activeTenant = this.getActiveTenant(cosmosName);
|
|
1756
2326
|
if (activeTenant) {
|
|
@@ -1767,7 +2337,11 @@ export class SpaceGibShellService {
|
|
|
1767
2337
|
}
|
|
1768
2338
|
case 'cosmos': {
|
|
1769
2339
|
if (this.cosmosNavigatorInstance) {
|
|
1770
|
-
const cosmos = await this.cosmosNavigatorInstance.
|
|
2340
|
+
const cosmos = await this.cosmosNavigatorInstance.findCosmos(route.cosmos);
|
|
2341
|
+
if (!cosmos) {
|
|
2342
|
+
this.show404(`Cosmos "${route.cosmos}" not found.`);
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
1771
2345
|
this.cosmosNavigatorInstance.selectCosmos(cosmos.id);
|
|
1772
2346
|
this.updateActiveCosmosDisplay(cosmos);
|
|
1773
2347
|
}
|
|
@@ -1776,60 +2350,46 @@ export class SpaceGibShellService {
|
|
|
1776
2350
|
await this.showCosmos();
|
|
1777
2351
|
break;
|
|
1778
2352
|
}
|
|
1779
|
-
case '
|
|
2353
|
+
case 'galaxy': {
|
|
2354
|
+
let cosmosInfo: CosmosInfo | undefined;
|
|
1780
2355
|
if (this.cosmosNavigatorInstance) {
|
|
1781
|
-
|
|
1782
|
-
if (!
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
type: 'code',
|
|
1786
|
-
name: 'Code Space 1',
|
|
1787
|
-
shortLabel: 'Code 1',
|
|
1788
|
-
icon: '</>',
|
|
1789
|
-
});
|
|
2356
|
+
cosmosInfo = await this.cosmosNavigatorInstance.findCosmos(route.cosmos);
|
|
2357
|
+
if (!cosmosInfo) {
|
|
2358
|
+
this.show404(`Cosmos "${route.cosmos}" not found.`);
|
|
2359
|
+
return;
|
|
1790
2360
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
if (route.branch && this.fileExplorerInstance) {
|
|
1800
|
-
this.fileExplorerInstance.setBranch(route.branch);
|
|
1801
|
-
}
|
|
1802
|
-
if (route.filePath && this.fileExplorerInstance) {
|
|
1803
|
-
this.fileExplorerInstance.selectFile(route.filePath);
|
|
1804
|
-
}
|
|
1805
|
-
await this.showCode(route.filePath, route.branch);
|
|
1806
|
-
break;
|
|
1807
|
-
}
|
|
1808
|
-
case 'notes-galaxy': {
|
|
1809
|
-
if (this.cosmosNavigatorInstance) {
|
|
1810
|
-
const cosmos = await this.cosmosNavigatorInstance.ensureCosmos(route.cosmos);
|
|
1811
|
-
if (!cosmos.spaces.some(s => s.type === 'text' || s.id === route.galaxyId)) {
|
|
1812
|
-
cosmos.spaces.push({
|
|
1813
|
-
id: route.galaxyId || 'notes-1',
|
|
1814
|
-
type: 'text',
|
|
1815
|
-
name: 'Text Space 1',
|
|
1816
|
-
shortLabel: 'Text 1',
|
|
1817
|
-
icon: '📝',
|
|
2361
|
+
const spaceType = route.topology === 'branching' ? 'code' : 'text';
|
|
2362
|
+
if (!cosmosInfo.spaces.some(s => s.id === route.galaxy)) {
|
|
2363
|
+
cosmosInfo.spaces.push({
|
|
2364
|
+
id: route.galaxy,
|
|
2365
|
+
type: spaceType,
|
|
2366
|
+
name: route.galaxy,
|
|
2367
|
+
shortLabel: route.galaxy,
|
|
2368
|
+
icon: route.topology === 'branching' ? '</>' : '📝',
|
|
1818
2369
|
});
|
|
1819
2370
|
}
|
|
1820
|
-
this.cosmosNavigatorInstance.selectCosmos(
|
|
1821
|
-
this.updateActiveCosmosDisplay(
|
|
2371
|
+
this.cosmosNavigatorInstance.selectCosmos(cosmosInfo.id);
|
|
2372
|
+
this.updateActiveCosmosDisplay(cosmosInfo, route.galaxy || spaceType);
|
|
1822
2373
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2374
|
+
|
|
2375
|
+
const policy: GalaxyPolicy = {
|
|
2376
|
+
topology: route.topology,
|
|
2377
|
+
role: route.topology === 'branching' ? 'intrinsic' : 'extrinsic',
|
|
2378
|
+
storageMode: 'text',
|
|
2379
|
+
defaultBranch: 'main',
|
|
2380
|
+
};
|
|
2381
|
+
|
|
2382
|
+
const context: PanelLoadContext = {
|
|
2383
|
+
route,
|
|
2384
|
+
cosmosName: route.cosmos,
|
|
2385
|
+
galaxyName: route.galaxy,
|
|
2386
|
+
discriminator: route.discriminator,
|
|
2387
|
+
policy,
|
|
2388
|
+
cosmosInfo,
|
|
2389
|
+
shell: this,
|
|
2390
|
+
};
|
|
2391
|
+
|
|
2392
|
+
await this.loadRouteForPanels(route, context);
|
|
1833
2393
|
break;
|
|
1834
2394
|
}
|
|
1835
2395
|
case 'raw-addr': {
|
|
@@ -1858,7 +2418,11 @@ export class SpaceGibShellService {
|
|
|
1858
2418
|
try {
|
|
1859
2419
|
console.log(`${lc} Resolving raw snapshot route: cosmos=${route.cosmos}, spaceId=${route.spaceId}, addr=${route.ibGibAddr}`);
|
|
1860
2420
|
if (this.cosmosNavigatorInstance) {
|
|
1861
|
-
const cosmos = await this.cosmosNavigatorInstance.
|
|
2421
|
+
const cosmos = await this.cosmosNavigatorInstance.findCosmos(route.cosmos);
|
|
2422
|
+
if (!cosmos) {
|
|
2423
|
+
this.show404(`Cosmos "${route.cosmos}" not found.`);
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
1862
2426
|
this.cosmosNavigatorInstance.selectCosmos(cosmos.id);
|
|
1863
2427
|
this.updateActiveCosmosDisplay(cosmos);
|
|
1864
2428
|
}
|
|
@@ -1899,7 +2463,11 @@ export class SpaceGibShellService {
|
|
|
1899
2463
|
try {
|
|
1900
2464
|
console.log(`${lc} Resolving living tip route: cosmos=${route.cosmos}, spaceId=${route.spaceId}, tjp=${route.tjpAddr}`);
|
|
1901
2465
|
if (this.cosmosNavigatorInstance) {
|
|
1902
|
-
const cosmos = await this.cosmosNavigatorInstance.
|
|
2466
|
+
const cosmos = await this.cosmosNavigatorInstance.findCosmos(route.cosmos);
|
|
2467
|
+
if (!cosmos) {
|
|
2468
|
+
this.show404(`Cosmos "${route.cosmos}" not found.`);
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
1903
2471
|
this.cosmosNavigatorInstance.selectCosmos(cosmos.id);
|
|
1904
2472
|
this.updateActiveCosmosDisplay(cosmos);
|
|
1905
2473
|
}
|