feat: sort briefs by updated at (#1409)

This commit is contained in:
Ralph Khreish
2025-11-15 12:15:07 +01:00
committed by GitHub
parent 3c6642b251
commit 26f77c207b
7 changed files with 52 additions and 9 deletions

View File

@@ -3,12 +3,13 @@
* Reusable functions for selecting briefs interactively or via URL/ID * Reusable functions for selecting briefs interactively or via URL/ID
*/ */
import chalk from 'chalk';
import search from '@inquirer/search'; import search from '@inquirer/search';
import ora, { Ora } from 'ora'; import type { AuthManager } from '@tm/core';
import { AuthManager } from '@tm/core'; import { formatRelativeTime } from '@tm/core';
import * as ui from './ui.js'; import chalk from 'chalk';
import ora, { type Ora } from 'ora';
import { getBriefStatusWithColor } from '../ui/formatters/status-formatters.js'; import { getBriefStatusWithColor } from '../ui/formatters/status-formatters.js';
import * as ui from './ui.js';
export interface BriefSelectionResult { export interface BriefSelectionResult {
success: boolean; success: boolean;
@@ -122,8 +123,12 @@ export async function selectBriefInteractive(
) )
: ''; : '';
const updatedAtDisplay = brief.updatedAt
? chalk.gray(`${formatRelativeTime(brief.updatedAt)}`)
: '';
groupedOptions.push({ groupedOptions.push({
name: ` ${title}${taskCountDisplay} ${chalk.gray(`(${shortId})`)}`, name: ` ${title}${taskCountDisplay} ${chalk.gray(`(${shortId})`)}${updatedAtDisplay}`,
value: brief, value: brief,
description: description description: description
? chalk.gray(` ${description.slice(0, 80)}`) ? chalk.gray(` ${description.slice(0, 80)}`)
@@ -158,8 +163,12 @@ export async function selectBriefInteractive(
) )
: ''; : '';
const updatedAtDisplay = brief.updatedAt
? chalk.gray(`${formatRelativeTime(brief.updatedAt)}`)
: '';
groupedOptions.push({ groupedOptions.push({
name: ` ${title}${taskCountDisplay} ${chalk.gray(`(${shortId})`)}`, name: ` ${title}${taskCountDisplay} ${chalk.gray(`(${shortId})`)}${updatedAtDisplay}`,
value: brief, value: brief,
description: description description: description
? chalk.gray(` ${description.slice(0, 80)}`) ? chalk.gray(` ${description.slice(0, 80)}`)

12
package-lock.json generated
View File

@@ -45,6 +45,7 @@
"cli-table3": "^0.6.5", "cli-table3": "^0.6.5",
"commander": "^12.1.0", "commander": "^12.1.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0",
"dotenv": "^16.6.1", "dotenv": "^16.6.1",
"express": "^4.21.2", "express": "^4.21.2",
"fastmcp": "^3.23.0", "fastmcp": "^3.23.0",
@@ -13239,6 +13240,16 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"license": "MIT", "license": "MIT",
@@ -28729,6 +28740,7 @@
"name": "@tm/core", "name": "@tm/core",
"dependencies": { "dependencies": {
"@supabase/supabase-js": "^2.57.4", "@supabase/supabase-js": "^2.57.4",
"date-fns": "^4.1.0",
"fs-extra": "^11.3.2", "fs-extra": "^11.3.2",
"simple-git": "^3.28.0", "simple-git": "^3.28.0",
"steno": "^4.0.2", "steno": "^4.0.2",

View File

@@ -83,6 +83,7 @@
"cli-table3": "^0.6.5", "cli-table3": "^0.6.5",
"commander": "^12.1.0", "commander": "^12.1.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0",
"dotenv": "^16.6.1", "dotenv": "^16.6.1",
"express": "^4.21.2", "express": "^4.21.2",
"fastmcp": "^3.23.0", "fastmcp": "^3.23.0",

View File

@@ -31,6 +31,7 @@
}, },
"dependencies": { "dependencies": {
"@supabase/supabase-js": "^2.57.4", "@supabase/supabase-js": "^2.57.4",
"date-fns": "^4.1.0",
"fs-extra": "^11.3.2", "fs-extra": "^11.3.2",
"simple-git": "^3.28.0", "simple-git": "^3.28.0",
"steno": "^4.0.2", "steno": "^4.0.2",

View File

@@ -50,6 +50,7 @@ export * from './common/errors/index.js';
// Utils // Utils
export * from './common/utils/index.js'; export * from './common/utils/index.js';
export * from './utils/time.utils.js';
// ========== Domain-Specific Type Exports ========== // ========== Domain-Specific Type Exports ==========

View File

@@ -3,13 +3,13 @@
* Handles fetching and managing organizations and briefs from the API * Handles fetching and managing organizations and briefs from the API
*/ */
import { SupabaseClient } from '@supabase/supabase-js'; import type { SupabaseClient } from '@supabase/supabase-js';
import { import {
ERROR_CODES, ERROR_CODES,
TaskMasterError TaskMasterError
} from '../../../common/errors/task-master-error.js'; } from '../../../common/errors/task-master-error.js';
import { getLogger } from '../../../common/logger/index.js'; import { getLogger } from '../../../common/logger/index.js';
import { Database } from '../../../common/types/database.types.js'; import type { Database } from '../../../common/types/database.types.js';
import type { Brief } from '../../briefs/types.js'; import type { Brief } from '../../briefs/types.js';
/** /**
@@ -171,7 +171,8 @@ export class OrganizationService {
title title
) )
`) `)
.eq('account_id', orgId); .eq('account_id', orgId)
.order('updated_at', { ascending: false });
if (error) { if (error) {
throw new TaskMasterError( throw new TaskMasterError(

View File

@@ -0,0 +1,18 @@
/**
* @fileoverview Time utilities for formatting relative timestamps
* Shared across CLI, MCP, extension, and other interfaces
*/
import { formatDistanceToNow } from 'date-fns';
/**
* Format a date as relative time from now (e.g., "2 hours ago", "3 days ago")
* @param date - Date string or Date object to format
* @returns Relative time string (e.g., "less than a minute ago", "5 minutes ago", "2 weeks ago")
*/
export function formatRelativeTime(date: string | Date): string {
const dateObj = typeof date === 'string' ? new Date(date) : date;
// Use date-fns for robust formatting with proper edge case handling
return formatDistanceToNow(dateObj, { addSuffix: true });
}