feat: what is new since my last visit, and turning a comment into a ticket
Opening a ticket notes the visit and answers the one before (issue_visits), so the page marks others' comments and changes since. A comment can become a ticket of its own, as a subtask or linked; it remembers where it went. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,7 @@ const commentFromDoc = (doc: CommentDoc): CommentReadModel => ({
|
||||
resolved: doc.resolved ?? false,
|
||||
resolvedBy: doc.resolvedBy ?? null,
|
||||
resolvedAt: doc.resolvedAt ?? null,
|
||||
spawned: doc.spawned ?? [],
|
||||
});
|
||||
|
||||
const escapeRegex = (text: string) =>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import {
|
||||
IssueVisit,
|
||||
IssueVisitsRepository,
|
||||
} from '@task-stream/api/tracker/application';
|
||||
import { Model } from 'mongoose';
|
||||
import { ReadModels } from './read-model.schemas';
|
||||
|
||||
@Injectable()
|
||||
export class MongoIssueVisitsRepository extends IssueVisitsRepository {
|
||||
constructor(
|
||||
@InjectModel(ReadModels.IssueVisit)
|
||||
private readonly visits: Model<IssueVisit>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async visit(visit: IssueVisit): Promise<string | null> {
|
||||
// One round trip: the document as it was before this visit.
|
||||
const before = await this.visits
|
||||
.findOneAndUpdate(
|
||||
{ userId: visit.userId, issueId: visit.issueId },
|
||||
{ $set: { seenAt: visit.seenAt } },
|
||||
{ upsert: true, new: false },
|
||||
)
|
||||
.lean<IssueVisit>();
|
||||
return before?.seenAt ?? null;
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,7 @@ export const ReadModels = {
|
||||
AlertIntegration: 'AlertIntegration',
|
||||
AlertTrace: 'AlertTrace',
|
||||
TreeFollow: 'TreeFollow',
|
||||
IssueVisit: 'IssueVisit',
|
||||
IssueReminder: 'IssueReminder',
|
||||
MyDay: 'MyDay',
|
||||
ReleaseNotesShare: 'ReleaseNotesShare',
|
||||
@@ -373,6 +374,16 @@ export const TreeFollowSchema =
|
||||
SchemaFactory.createForClass(TreeFollowDocument);
|
||||
TreeFollowSchema.index({ userId: 1, issueId: 1 }, { unique: true });
|
||||
|
||||
@Schema({ ...LOOSE, collection: 'issue_visits' })
|
||||
class IssueVisitDocument {
|
||||
@Prop({ type: String }) userId!: string;
|
||||
@Prop({ type: String }) issueId!: string;
|
||||
@Prop({ type: String }) seenAt!: string;
|
||||
}
|
||||
export const IssueVisitSchema =
|
||||
SchemaFactory.createForClass(IssueVisitDocument);
|
||||
IssueVisitSchema.index({ userId: 1, issueId: 1 }, { unique: true });
|
||||
|
||||
@Schema({ ...LOOSE, collection: 'issue_reminders' })
|
||||
class IssueReminderDocument {
|
||||
@Prop({ type: String, required: true, unique: true }) id!: string;
|
||||
@@ -511,6 +522,7 @@ export const READ_MODEL_SCHEMAS = [
|
||||
{ name: ReadModels.AlertIntegration, schema: AlertIntegrationSchema },
|
||||
{ name: ReadModels.AlertTrace, schema: AlertTraceSchema },
|
||||
{ name: ReadModels.TreeFollow, schema: TreeFollowSchema },
|
||||
{ name: ReadModels.IssueVisit, schema: IssueVisitSchema },
|
||||
{ name: ReadModels.IssueReminder, schema: IssueReminderSchema },
|
||||
{ name: ReadModels.MyDay, schema: MyDaySchema },
|
||||
{ name: ReadModels.ReleaseNotesShare, schema: ReleaseNotesShareSchema },
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
PinsRepository,
|
||||
AlertIntegrationsRepository,
|
||||
TreeFollowsRepository,
|
||||
IssueVisitsRepository,
|
||||
IssueRemindersRepository,
|
||||
MyDaysRepository,
|
||||
ReleaseNoteSharesRepository,
|
||||
@@ -87,6 +88,7 @@ import { MongoMyViewsRepository } from './mongo/my-views.repository';
|
||||
import { MongoPinsRepository } from './mongo/pins.repository';
|
||||
import { MongoAlertIntegrationsRepository } from './mongo/alert-integrations.repository';
|
||||
import { MongoTreeFollowsRepository } from './mongo/tree-follows.repository';
|
||||
import { MongoIssueVisitsRepository } from './mongo/issue-visits.repository';
|
||||
import { MongoIssueRemindersRepository } from './mongo/issue-reminders.repository';
|
||||
import { MongoMyDaysRepository } from './mongo/my-days.repository';
|
||||
import { MongoReleaseNoteSharesRepository } from './mongo/release-note-shares.repository';
|
||||
@@ -172,6 +174,7 @@ const PORTS = [
|
||||
useClass: MongoAlertIntegrationsRepository,
|
||||
},
|
||||
{ provide: TreeFollowsRepository, useClass: MongoTreeFollowsRepository },
|
||||
{ provide: IssueVisitsRepository, useClass: MongoIssueVisitsRepository },
|
||||
{
|
||||
provide: IssueRemindersRepository,
|
||||
useClass: MongoIssueRemindersRepository,
|
||||
|
||||
Reference in New Issue
Block a user