mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 12:40:44 +00:00
feat(webui): migrate pure UI ToolCall components and add Storybook stories
- Migrate ThinkToolCall, GenericToolCall, EditToolCall, WriteToolCall, SearchToolCall, UpdatedPlanToolCall, CheckboxDisplay to webui - Add Storybook stories for all migrated components - Add stories for shared components (ToolCallContainer, ToolCallCard, StatusIndicator, CodeBlock, LocationsList, CopyButton) - Fix Storybook theme by reordering CSS imports and adding body color - Update vscode-ide-companion to import ToolCall components from webui - Keep ReadToolCall and ShellToolCall in vscode-ide-companion (VSCode deps)
This commit is contained in:
parent
c44a60f9f9
commit
593577864b
53 changed files with 3089 additions and 575 deletions
126
packages/webui/src/utils/sessionGrouping.ts
Normal file
126
packages/webui/src/utils/sessionGrouping.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Session grouping utilities
|
||||
* Functions for organizing sessions by date and formatting time ago
|
||||
*/
|
||||
|
||||
/**
|
||||
* Session group structure
|
||||
*/
|
||||
export interface SessionGroup {
|
||||
/** Group label (e.g., "Today", "Yesterday") */
|
||||
label: string;
|
||||
/** Sessions in this group */
|
||||
sessions: Array<Record<string, unknown>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group sessions by date
|
||||
*
|
||||
* Categories:
|
||||
* - Today: Sessions from today
|
||||
* - Yesterday: Sessions from yesterday
|
||||
* - This Week: Sessions from the last 7 days (excluding today/yesterday)
|
||||
* - Older: Sessions older than a week
|
||||
*
|
||||
* @param sessions - Array of session objects (must have lastUpdated or startTime)
|
||||
* @returns Array of grouped sessions, only includes non-empty groups
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const grouped = groupSessionsByDate(sessions);
|
||||
* // [{ label: 'Today', sessions: [...] }, { label: 'Older', sessions: [...] }]
|
||||
* ```
|
||||
*/
|
||||
export const groupSessionsByDate = (
|
||||
sessions: Array<Record<string, unknown>>,
|
||||
): SessionGroup[] => {
|
||||
const now = new Date();
|
||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const groups: {
|
||||
[key: string]: Array<Record<string, unknown>>;
|
||||
} = {
|
||||
Today: [],
|
||||
Yesterday: [],
|
||||
'This Week': [],
|
||||
Older: [],
|
||||
};
|
||||
|
||||
sessions.forEach((session) => {
|
||||
const timestamp =
|
||||
(session.lastUpdated as string) || (session.startTime as string) || '';
|
||||
if (!timestamp) {
|
||||
groups['Older'].push(session);
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionDate = new Date(timestamp);
|
||||
const sessionDay = new Date(
|
||||
sessionDate.getFullYear(),
|
||||
sessionDate.getMonth(),
|
||||
sessionDate.getDate(),
|
||||
);
|
||||
|
||||
if (sessionDay.getTime() === today.getTime()) {
|
||||
groups['Today'].push(session);
|
||||
} else if (sessionDay.getTime() === yesterday.getTime()) {
|
||||
groups['Yesterday'].push(session);
|
||||
} else if (sessionDay.getTime() > today.getTime() - 7 * 86400000) {
|
||||
groups['This Week'].push(session);
|
||||
} else {
|
||||
groups['Older'].push(session);
|
||||
}
|
||||
});
|
||||
|
||||
return Object.entries(groups)
|
||||
.filter(([, sessions]) => sessions.length > 0)
|
||||
.map(([label, sessions]) => ({ label, sessions }));
|
||||
};
|
||||
|
||||
/**
|
||||
* Format timestamp as relative time string
|
||||
*
|
||||
* @param timestamp - ISO timestamp string
|
||||
* @returns Formatted relative time (e.g., "now", "5m", "2h", "Yesterday", "3d", or date)
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* getTimeAgo(new Date().toISOString()) // "now"
|
||||
* getTimeAgo(thirtyMinutesAgo.toISOString()) // "30m"
|
||||
* getTimeAgo(twoHoursAgo.toISOString()) // "2h"
|
||||
* ```
|
||||
*/
|
||||
export const getTimeAgo = (timestamp: string): string => {
|
||||
if (!timestamp) {
|
||||
return '';
|
||||
}
|
||||
const now = new Date().getTime();
|
||||
const then = new Date(timestamp).getTime();
|
||||
const diffMs = now - then;
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const diffHours = Math.floor(diffMs / 3600000);
|
||||
const diffDays = Math.floor(diffMs / 86400000);
|
||||
|
||||
if (diffMins < 1) {
|
||||
return 'now';
|
||||
}
|
||||
if (diffMins < 60) {
|
||||
return `${diffMins}m`;
|
||||
}
|
||||
if (diffHours < 24) {
|
||||
return `${diffHours}h`;
|
||||
}
|
||||
if (diffDays === 1) {
|
||||
return 'Yesterday';
|
||||
}
|
||||
if (diffDays < 7) {
|
||||
return `${diffDays}d`;
|
||||
}
|
||||
return new Date(timestamp).toLocaleDateString();
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue