Skip to content

Commit a05c34b

Browse files
committed
Caches Org AI settings in local storage
(#4300, #4338)
1 parent 48ef2bf commit a05c34b

File tree

2 files changed

+63
-5
lines changed

2 files changed

+63
-5
lines changed

src/constants.storage.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { GroupableTreeViewTypes } from './constants.views';
77
import type { Environment } from './container';
88
import type { FeaturePreviews } from './features';
99
import type { GitRevisionRangeNotation } from './git/models/revision';
10+
import type { OrganizationSettings } from './plus/gk/models/organization';
1011
import type { PaidSubscriptionPlanIds, Subscription } from './plus/gk/models/subscription';
1112
import type { IntegrationConnectedKey } from './plus/integrations/models/integration';
1213
import type { DeepLinkServiceState } from './uris/deepLinks/deepLink';
@@ -89,6 +90,10 @@ export type GlobalStorage = {
8990
'views:scm:grouped:welcome:dismissed': boolean;
9091
'integrations:configured': StoredIntegrationConfigurations;
9192
} & { [key in `plus:preview:${FeaturePreviews}:usages`]: StoredFeaturePreviewUsagePeriod[] } & {
93+
[key in `plus:organization:${string}:settings`]: Stored<
94+
(OrganizationSettings & { lastValidatedAt: number }) | undefined
95+
>;
96+
} & {
9297
[key in `provider:authentication:skip:${string}`]: boolean;
9398
} & { [key in `gk:${string}:checkin`]: Stored<StoredGKCheckInResponse> } & {
9499
[key in `gk:${string}:organizations`]: Stored<StoredOrganization[]>;

src/plus/gk/organizationService.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ const organizationsCacheExpiration = 24 * 60 * 60 * 1000; // 1 day
2020
export class OrganizationService implements Disposable {
2121
private _disposable: Disposable;
2222
private _organizations: Organization[] | null | undefined;
23-
private _organizationSettings: Map<Organization['id'], OrganizationSettings> | undefined;
23+
private _organizationSettings:
24+
| Map<Organization['id'], { data: OrganizationSettings; lastValidatedDate: Date }>
25+
| undefined;
2426
private _organizationMembers: Map<Organization['id'], OrganizationMember[]> | undefined;
2527

2628
constructor(
@@ -126,11 +128,12 @@ export class OrganizationService implements Disposable {
126128
});
127129
}
128130

129-
private onSubscriptionChanged(e: SubscriptionChangeEvent): void {
131+
private async onSubscriptionChanged(e: SubscriptionChangeEvent): Promise<void> {
130132
if (e.current?.account?.id == null) {
131133
this.updateOrganizations(undefined);
132134
}
133-
void this.updateOrganizationPermissions(e.current?.activeOrganization?.id);
135+
await this.clearAllStoredOrganizationsSettings();
136+
await this.updateOrganizationPermissions(e.current?.activeOrganization?.id);
134137
}
135138

136139
private updateOrganizations(organizations: Organization[] | null | undefined): void {
@@ -217,7 +220,23 @@ export class OrganizationService implements Disposable {
217220
const id = orgId ?? (await this.getActiveOrganizationId());
218221
if (id == null) return undefined;
219222

223+
if (!options?.force && !this._organizationSettings?.has(id)) {
224+
const cachedOrg = this.getStoredOrganizationSettings(id);
225+
if (cachedOrg) {
226+
this._organizationSettings ??= new Map();
227+
this._organizationSettings.set(id, cachedOrg);
228+
}
229+
}
230+
231+
if (this._organizationSettings?.has(id)) {
232+
const org = this._organizationSettings.get(id);
233+
if (org && Date.now() - org.lastValidatedDate.getTime() > organizationsCacheExpiration) {
234+
this._organizationSettings.delete(id);
235+
}
236+
}
237+
220238
if (!this._organizationSettings?.has(id) || options?.force === true) {
239+
await this.deleteStoredOrganizationSettings(id);
221240
const rsp = await this.connection.fetchGkApi(
222241
`v1/organizations/settings`,
223242
{ method: 'GET' },
@@ -245,9 +264,43 @@ export class OrganizationService implements Disposable {
245264
if (this._organizationSettings == null) {
246265
this._organizationSettings = new Map();
247266
}
248-
this._organizationSettings.set(id, organizationResponse.data);
267+
this._organizationSettings.set(id, { data: organizationResponse.data, lastValidatedDate: new Date() });
268+
await this.storeOrganizationSettings(id, organizationResponse.data, new Date());
249269
}
250-
return this._organizationSettings.get(id);
270+
return this._organizationSettings.get(id)?.data;
271+
}
272+
273+
private async clearAllStoredOrganizationsSettings(): Promise<void> {
274+
return this.container.storage.deleteWithPrefix(`plus:organization:`);
275+
}
276+
277+
private async deleteStoredOrganizationSettings(id: string): Promise<void> {
278+
return this.container.storage.delete(`plus:organization:${id}:settings`);
279+
}
280+
281+
private getStoredOrganizationSettings(
282+
id: string,
283+
): { data: OrganizationSettings; lastValidatedDate: Date } | undefined {
284+
const result = this.container.storage.get(`plus:organization:${id}:settings`);
285+
if (!result?.data) return undefined;
286+
287+
const { lastValidatedAt, ...organizationSettings } = result.data;
288+
289+
return {
290+
data: organizationSettings,
291+
lastValidatedDate: new Date(lastValidatedAt),
292+
};
293+
}
294+
295+
private async storeOrganizationSettings(
296+
id: string,
297+
settings: OrganizationSettings,
298+
lastValidatedDate: Date,
299+
): Promise<void> {
300+
return this.container.storage.store(`plus:organization:${id}:settings`, {
301+
v: 1,
302+
data: { ...settings, lastValidatedAt: lastValidatedDate.getTime() },
303+
});
251304
}
252305
}
253306

0 commit comments

Comments
 (0)