0.10.1: Archify Sync in the status bar, server address as a setting
In workspaces with Archify files, Archify Sync sits in the status bar and opens a menu: sign in, share, join, server address, settings. The new archify.sync.server setting (empty by default) is used without asking, and in workspace settings gives a project one server. archify.sync.statusBar hides the entry.
This commit is contained in:
1 parent
d02c331155
commit
9ccd67b2dd
7 files changed
+135
-19
No files matched your search
+80
-10
@@ -23,6 +23,7 @@ export const SYNC_COMMANDS = [
|
||||
'archify.sync.versions',
|
||||
'archify.sync.stop',
|
||||
'archify.sync.menu',
|
||||
'archify.sync.setServer',
|
||||
] as const;
|
||||
|
||||
const SKIP = '{**/node_modules/**,**/.git/**}';
|
||||
@@ -38,6 +39,10 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
private readonly versionCache = new Map<string, { at: number; versions: Promise<Version[]> }>();
|
||||
private readonly editorCursors: EditorCursors;
|
||||
private cursorTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
/** Servers with a session on this machine, for the status bar before any model is shared. */
|
||||
private signedIn: string[] = [];
|
||||
/** Whether the workspace has Archify files; elsewhere the entry stays hidden until a model is shared. */
|
||||
private archifyHere = false;
|
||||
|
||||
constructor(
|
||||
private readonly context: vscode.ExtensionContext,
|
||||
@@ -62,8 +67,9 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
vscode.workspace.registerTextDocumentContentProvider(VERSION_SCHEME, this.content),
|
||||
this.auth.onDidChangeSessions(() => {
|
||||
for (const space of this.spaces.values()) space.reconnect();
|
||||
this.render();
|
||||
void this.refreshSignedIn();
|
||||
}),
|
||||
vscode.workspace.onDidChangeConfiguration((e) => e.affectsConfiguration('archify.sync') && this.render()),
|
||||
);
|
||||
this.editorCursors = new EditorCursors({ cursors: (file) => this.cursors(file), setCursor: (file, selection) => this.setCursorIn(file, selection) });
|
||||
this.disposables.push(this.editorCursors);
|
||||
@@ -74,6 +80,12 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
async start(): Promise<void> {
|
||||
const found = await vscode.workspace.findFiles(`**/${LINK_FILE}`, SKIP, 50);
|
||||
await Promise.all(found.map((uri) => this.open(uri, 'open')));
|
||||
this.archifyHere = (await vscode.workspace.findFiles('**/*.{archify,archify-registry,archify-decision}', SKIP, 1)).length > 0;
|
||||
await this.refreshSignedIn();
|
||||
}
|
||||
|
||||
private async refreshSignedIn(): Promise<void> {
|
||||
this.signedIn = await this.auth.servers();
|
||||
this.render();
|
||||
}
|
||||
|
||||
@@ -127,8 +139,20 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
private render(): void {
|
||||
const spaces = [...this.spaces.values()];
|
||||
if (!spaces.length) {
|
||||
this.status.hide();
|
||||
void vscode.commands.executeCommand('setContext', 'archify.sync.active', false);
|
||||
// Nothing shared here yet: the way in, as before the sync bundle loaded.
|
||||
if (!this.archifyHere || !vscode.workspace.getConfiguration('archify.sync').get<boolean>('statusBar', true)) {
|
||||
this.status.hide();
|
||||
return;
|
||||
}
|
||||
const hosts = this.signedIn.map((server) => new URL(server).host);
|
||||
this.status.text = hosts.length ? `$(cloud) Archify Sync · ${hosts.join(', ')}` : '$(cloud) Archify Sync';
|
||||
this.status.tooltip = hosts.length
|
||||
? `Signed in to ${hosts.join(', ')}. Click to share a model, join one or sign out.`
|
||||
: 'Archify Sync (optional): sign in, share a model with others or join one. Set the server under Settings › Archify › Sync.';
|
||||
this.status.backgroundColor = undefined;
|
||||
this.status.show();
|
||||
this.bridge?.changed();
|
||||
return;
|
||||
}
|
||||
void vscode.commands.executeCommand('setContext', 'archify.sync.active', true);
|
||||
@@ -300,6 +324,9 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
case 'archify.sync.menu':
|
||||
await this.menu();
|
||||
break;
|
||||
case 'archify.sync.setServer':
|
||||
await this.setServer();
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
this.report(error);
|
||||
@@ -319,8 +346,13 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
else if (uri.path === '/join') await this.run('archify.sync.join', uri.toString(true));
|
||||
}
|
||||
|
||||
/** The server from the archify.sync.server setting, or asked for (and remembered). */
|
||||
private async askServer(): Promise<string | undefined> {
|
||||
const last = this.context.globalState.get<string>('archifySync.lastServer');
|
||||
return configuredServer() ?? this.promptServer();
|
||||
}
|
||||
|
||||
private async promptServer(): Promise<string | undefined> {
|
||||
const last = configuredServer() ?? this.context.globalState.get<string>('archifySync.lastServer');
|
||||
const value = await vscode.window.showInputBox({
|
||||
title: 'Archify | Sync server',
|
||||
prompt: 'The address of the Archify Sync server',
|
||||
@@ -350,6 +382,16 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Writes archify.sync.server: in the workspace when the workspace sets it, otherwise for the user. */
|
||||
private async setServer(): Promise<void> {
|
||||
const server = await this.promptServer();
|
||||
if (!server) return;
|
||||
const config = vscode.workspace.getConfiguration('archify.sync');
|
||||
const inWorkspace = config.inspect<string>('server')?.workspaceValue !== undefined;
|
||||
await config.update('server', server, inWorkspace ? vscode.ConfigurationTarget.Workspace : vscode.ConfigurationTarget.Global);
|
||||
vscode.window.showInformationMessage(`Archify Sync: server set to ${new URL(server).host}${inWorkspace ? ' for this workspace' : ''}.`);
|
||||
}
|
||||
|
||||
private async signInCommand(): Promise<void> {
|
||||
const server = await this.askServer();
|
||||
if (!server || !(await this.checkServer(server))) return;
|
||||
@@ -531,7 +573,10 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
private async menu(): Promise<void> {
|
||||
const spaces = [...this.spaces.values()];
|
||||
const signedOut = spaces.find((s) => s.state === 'signed-out');
|
||||
const items: (vscode.QuickPickItem & { run: () => Promise<void> })[] = [];
|
||||
const servers = await this.auth.servers();
|
||||
const configured = configuredServer();
|
||||
type Item = vscode.QuickPickItem & { run?: () => Promise<void> };
|
||||
const items: Item[] = [];
|
||||
if (signedOut) {
|
||||
items.push({
|
||||
label: `$(account) Sign in to ${new URL(signedOut.link.server).host}`,
|
||||
@@ -539,16 +584,35 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
if (await this.checkServer(signedOut.link.server)) await this.auth.signIn(signedOut.link.server);
|
||||
},
|
||||
});
|
||||
} else if (!servers.length) {
|
||||
items.push({
|
||||
label: '$(account) Sign in…',
|
||||
description: configured ? new URL(configured).host : 'asks for the server address',
|
||||
run: () => this.signInCommand(),
|
||||
});
|
||||
}
|
||||
items.push(
|
||||
{ label: '$(person-add) Copy invite link…', run: () => this.invite(undefined) },
|
||||
{ label: '$(tag) Publish version…', run: () => this.publish(undefined) },
|
||||
{ label: '$(history) Versions…', run: () => this.run('archify.sync.versions') },
|
||||
{ label: '$(output) Show log', run: async () => this.log.show() },
|
||||
{ label: '$(debug-disconnect) Stop syncing a model…', run: () => this.stop(undefined) },
|
||||
{ label: '$(live-share) Share a model…', run: () => this.share(undefined) },
|
||||
{ label: '$(link) Join a shared model…', description: 'with an invite link', run: () => this.join(undefined) },
|
||||
);
|
||||
if (spaces.length) {
|
||||
items.push(
|
||||
{ label: 'Shared models', kind: vscode.QuickPickItemKind.Separator },
|
||||
{ label: '$(person-add) Copy invite link…', run: () => this.invite(undefined) },
|
||||
{ label: '$(tag) Publish version…', run: () => this.publish(undefined) },
|
||||
{ label: '$(history) Versions…', run: () => this.run('archify.sync.versions') },
|
||||
{ label: '$(debug-disconnect) Stop syncing a model…', run: () => this.stop(undefined) },
|
||||
);
|
||||
}
|
||||
items.push(
|
||||
{ label: 'Settings', kind: vscode.QuickPickItemKind.Separator },
|
||||
{ label: '$(server) Server address…', description: configured ? new URL(configured).host : 'not set', run: () => this.setServer() },
|
||||
{ label: '$(settings-gear) Open Sync settings', run: async () => void vscode.commands.executeCommand('workbench.action.openSettings', 'archify.sync') },
|
||||
{ label: '$(output) Show log', run: async () => this.log.show() },
|
||||
);
|
||||
if (servers.length) items.push({ label: '$(sign-out) Sign out…', description: servers.map((s) => new URL(s).host).join(', '), run: () => this.signOut() });
|
||||
const pick = await vscode.window.showQuickPick(items, { title: 'Archify Sync' });
|
||||
await pick?.run();
|
||||
await pick?.run?.();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -560,6 +624,12 @@ export class SyncFeature implements vscode.Disposable, LiveProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/** archify.sync.server when it holds a usable address. */
|
||||
function configuredServer(): string | undefined {
|
||||
const value = vscode.workspace.getConfiguration('archify.sync').get<string>('server', '').trim();
|
||||
return value ? checkServerUrl(value).url : undefined;
|
||||
}
|
||||
|
||||
/** The file behind the active tab when it is a custom editor (the Archify pages). */
|
||||
function activeTabUri(): vscode.Uri | undefined {
|
||||
const input = vscode.window.tabGroups.activeTabGroup.activeTab?.input;
|
||||
|
||||
Reference in new issue
Block a user