Parcourir la source

Adds timed snooze to the webview and service

main
Keith Daulton il y a 1 an
Parent
révision
7c8f43c4e6
2 fichiers modifiés avec 112 ajouts et 22 suppressions
  1. +11
    -4
      src/plus/focus/focusService.ts
  2. +101
    -18
      src/plus/webviews/focus/focusWebview.ts

+ 11
- 4
src/plus/focus/focusService.ts Voir le fichier

@ -14,6 +14,7 @@ export interface FocusItem {
id: string;
remote: GitRemote<RemoteProvider>;
url: string;
expiresAt?: string;
}
export type EnrichedItem = {
@ -26,8 +27,9 @@ export type EnrichedItem = {
entityId: string;
entityUrl: string;
createdAt: number;
updatedAt: number;
createdAt: string;
updatedAt: string;
expiresAt?: string;
};
type EnrichedItemRequest = {
@ -35,6 +37,7 @@ type EnrichedItemRequest = {
entityType: EnrichedItemResponse['entityType'];
entityId: string;
entityUrl: string;
expiresAt?: string;
};
type EnrichedItemResponse = {
@ -47,8 +50,9 @@ type EnrichedItemResponse = {
entityId: string;
entityUrl: string;
createdAt: number;
updatedAt: number;
createdAt: string;
updatedAt: string;
expiresAt?: string;
};
export class FocusService implements Disposable {
@ -163,6 +167,9 @@ export class FocusService implements Disposable {
entityId: item.id,
entityUrl: item.url,
};
if (item.expiresAt != null) {
rq.expiresAt = item.expiresAt;
}
const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/snooze', {
method: 'POST',

+ 101
- 18
src/plus/webviews/focus/focusWebview.ts Voir le fichier

@ -112,6 +112,10 @@ export class FocusWebviewProvider implements WebviewProvider {
}
dispose() {
if (this.enrichmentExpirationTimeout != null) {
clearTimeout(this.enrichmentExpirationTimeout);
this.enrichmentExpirationTimeout = undefined;
}
this._disposable.dispose();
}
@ -173,7 +177,7 @@ export class FocusWebviewProvider implements WebviewProvider {
}
@debug({ args: false })
private async onSnoozeIssue({ issue, snooze }: SnoozeIssueParams) {
private async onSnoozeIssue({ issue, snooze, expiresAt }: SnoozeIssueParams) {
const issueWithRemote = this._issues?.find(r => r.issue.nodeId === issue.nodeId);
if (issueWithRemote == null) return;
@ -188,6 +192,9 @@ export class FocusWebviewProvider implements WebviewProvider {
remote: issueWithRemote.repoAndRemote.remote,
url: issueWithRemote.issue.url,
};
if (expiresAt != null) {
focusItem.expiresAt = expiresAt;
}
const enrichedItem = await this.container.focus.snoozeItem(focusItem);
if (enrichedItem == null) return;
if (this._enrichedItems == null) {
@ -235,7 +242,7 @@ export class FocusWebviewProvider implements WebviewProvider {
}
@debug({ args: false })
private async onSnoozePr({ pullRequest, snooze }: SnoozePrParams) {
private async onSnoozePr({ pullRequest, snooze, expiresAt }: SnoozePrParams) {
const prWithRemote = this._pullRequests?.find(r => r.pullRequest.nodeId === pullRequest.nodeId);
if (prWithRemote == null) return;
@ -250,6 +257,9 @@ export class FocusWebviewProvider implements WebviewProvider {
remote: prWithRemote.repoAndRemote.remote,
url: prWithRemote.pullRequest.url,
};
if (expiresAt != null) {
focusItem.expiresAt = expiresAt;
}
const enrichedItem = await this.container.focus.snoozeItem(focusItem);
if (enrichedItem == null) return;
if (this._enrichedItems == null) {
@ -427,6 +437,47 @@ export class FocusWebviewProvider implements WebviewProvider {
return this._access;
}
private enrichmentExpirationTimeout?: ReturnType<typeof setTimeout>;
private ensureEnrichmentExpirationCore(appliedEnrichments?: EnrichedItem[]) {
if (this.enrichmentExpirationTimeout != null) {
clearTimeout(this.enrichmentExpirationTimeout);
this.enrichmentExpirationTimeout = undefined;
}
if (appliedEnrichments == null || appliedEnrichments.length === 0) return;
const nowTime = Date.now();
let expirableEnrichmentTime: number | undefined;
for (const item of appliedEnrichments) {
if (item.expiresAt == null) continue;
const expiresAtTime = new Date(item.expiresAt).getTime();
if (
expirableEnrichmentTime == null ||
(expiresAtTime > nowTime && expiresAtTime < expirableEnrichmentTime)
) {
expirableEnrichmentTime = expiresAtTime;
}
}
if (expirableEnrichmentTime == null) return;
const debounceTime = expirableEnrichmentTime + 1000 * 60 * 15; // 15 minutes
// find the item in appliedEnrichments with largest expiresAtTime that is less than the debounce time + expirableEnrichmentTime
for (const item of appliedEnrichments) {
if (item.expiresAt == null) continue;
const expiresAtTime = new Date(item.expiresAt).getTime();
if (expiresAtTime > expirableEnrichmentTime && expiresAtTime < debounceTime) {
expirableEnrichmentTime = expiresAtTime;
}
}
const expiresTimeout = expirableEnrichmentTime - nowTime + 60000;
this.enrichmentExpirationTimeout = setTimeout(() => {
void this.notifyDidChangeState(true);
}, expiresTimeout);
}
@debug()
private async getState(force?: boolean, deferState?: boolean): Promise<State> {
const baseState = this.host.baseWebviewState;
@ -469,30 +520,52 @@ export class FocusWebviewProvider implements WebviewProvider {
this.getEnrichedItems(force),
]);
async function getStateCore() {
const getStateCore = async () => {
const [prsResult, issuesResult, enrichedItems] = await statePromise;
return {
...baseState,
access: access,
repos: repos,
pullRequests: getSettledValue(prsResult)?.map(pr => ({
const appliedEnrichments: EnrichedItem[] = [];
const pullRequests = getSettledValue(prsResult)?.map(pr => {
const itemEnrichments = findEnrichedItems(pr, getSettledValue(enrichedItems));
if (itemEnrichments != null) {
appliedEnrichments.push(...itemEnrichments);
}
return {
pullRequest: serializePullRequest(pr.pullRequest),
reasons: pr.reasons,
isCurrentBranch: pr.isCurrentBranch ?? false,
isCurrentWorktree: pr.isCurrentWorktree ?? false,
hasWorktree: pr.hasWorktree ?? false,
hasLocalBranch: pr.hasLocalBranch ?? false,
enriched: findEnrichedItems(pr, getSettledValue(enrichedItems)),
enriched: serializeEnrichedItems(itemEnrichments),
rank: pr.rank,
})),
issues: getSettledValue(issuesResult)?.map(issue => ({
};
});
const issues = getSettledValue(issuesResult)?.map(issue => {
const itemEnrichments = findEnrichedItems(issue, getSettledValue(enrichedItems));
if (itemEnrichments != null) {
appliedEnrichments.push(...itemEnrichments);
}
return {
issue: serializeIssue(issue.issue),
reasons: issue.reasons,
enriched: findEnrichedItems(issue, getSettledValue(enrichedItems)),
enriched: serializeEnrichedItems(itemEnrichments),
rank: issue.rank,
})),
};
});
this.ensureEnrichmentExpirationCore(appliedEnrichments);
return {
...baseState,
access: access,
repos: repos,
pullRequests: pullRequests,
issues: issues,
};
}
};
if (deferState) {
queueMicrotask(async () => {
@ -705,7 +778,10 @@ function findEnrichedItems(
item: SearchedPullRequestWithRemote | SearchedIssueWithRank,
enrichedItems?: EnrichedItem[],
) {
if (enrichedItems == null || enrichedItems.length === 0) return;
if (enrichedItems == null || enrichedItems.length === 0) {
item.enriched = undefined;
return;
}
let result;
// TODO: filter by entity id, type, and gitRepositoryId
@ -719,10 +795,17 @@ function findEnrichedItems(
item.enriched = result;
return result.map(result => {
return result;
}
function serializeEnrichedItems(enrichedItems: EnrichedItem[] | undefined) {
if (enrichedItems == null || enrichedItems.length === 0) return;
return enrichedItems.map(enrichedItem => {
return {
id: result.id,
type: result.type,
id: enrichedItem.id,
type: enrichedItem.type,
expiresAt: enrichedItem.expiresAt,
};
});
}

Chargement…
Annuler
Enregistrer