From 7567abffccee45646374543ee54192ea2b864213 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 11 Aug 2025 16:47:08 -0500 Subject: [PATCH 1/4] add time range --- src/lib/helpers/constants.js | 20 +++++- src/lib/helpers/enums.js | 19 +++++- src/lib/helpers/types/conversationTypes.js | 5 ++ src/lib/helpers/types/instructTypes.js | 4 ++ src/lib/helpers/utils/common.js | 60 +++++++++++++++++ src/routes/page/conversation/+page.svelte | 68 ++++++++++++++------ src/routes/page/instruction/log/+page.svelte | 53 ++++++++++++--- 7 files changed, 199 insertions(+), 30 deletions(-) diff --git a/src/lib/helpers/constants.js b/src/lib/helpers/constants.js index 5ddcf6ac..1b21bac0 100644 --- a/src/lib/helpers/constants.js +++ b/src/lib/helpers/constants.js @@ -1,4 +1,4 @@ -import { EditorType, UserRole } from "./enums"; +import { EditorType, TimeRange, UserRole } from "./enums"; export const CHAT_FRAME_ID = "chatbox-frame"; @@ -45,4 +45,20 @@ export const DEFAULT_KNOWLEDGE_COLLECTION = "BotSharp"; export const IMAGE_DATA_PREFIX = 'data:image'; export const INTEGER_REGEX = "[0-9]+"; -export const DECIMAL_REGEX = "[0-9.]+"; \ No newline at end of file +export const DECIMAL_REGEX = "[0-9.]+"; + +export const TIME_RANGE_OPTIONS = [ + { label: TimeRange.Last15Minutes, value: TimeRange.Last15Minutes, qty: 15, unit: 'minutes' }, + { label: TimeRange.Last30Minutes, value: TimeRange.Last30Minutes, qty: 30, unit: 'minutes' }, + { label: TimeRange.Last1Hour, value: TimeRange.Last1Hour, qty: 1, unit: 'hours' }, + { label: TimeRange.Last3Hours, value: TimeRange.Last3Hours, qty: 3, unit: 'hours' }, + { label: TimeRange.Last12Hours, value: TimeRange.Last12Hours, qty: 12, unit: 'hours' }, + { label: TimeRange.Today, value: TimeRange.Today, qty: 1, unit: 'days' }, + { label: TimeRange.Yesterday, value: TimeRange.Yesterday, qty: 1, unit: 'days' }, + { label: TimeRange.Last3Days, value: TimeRange.Last3Days, qty: 3, unit: 'days' }, + { label: TimeRange.Last7Days, value: TimeRange.Last7Days, qty: 7, unit: 'days' }, + { label: TimeRange.Last30Days, value: TimeRange.Last30Days, qty: 30, unit: 'days' }, + { label: TimeRange.Last90Days, value: TimeRange.Last90Days, qty: 90, unit: 'days' }, + { label: TimeRange.Last180Days, value: TimeRange.Last180Days, qty: 180, unit: 'days' }, + { label: TimeRange.LastYear, value: TimeRange.LastYear, qty: 365, unit: 'days' } +]; \ No newline at end of file diff --git a/src/lib/helpers/enums.js b/src/lib/helpers/enums.js index 87011624..710d95ee 100644 --- a/src/lib/helpers/enums.js +++ b/src/lib/helpers/enums.js @@ -192,4 +192,21 @@ const reasoningEffortLevel = { Medium: "medium", High: "high" }; -export const ReasoningEffortLevel = Object.freeze(reasoningEffortLevel); \ No newline at end of file +export const ReasoningEffortLevel = Object.freeze(reasoningEffortLevel); + +const timeRange = { + Last15Minutes: "Last 15 minutes", + Last30Minutes: "Last 30 minutes", + Last1Hour: "Last 1 hour", + Last3Hours: "Last 3 hours", + Last12Hours: "Last 12 hours", + Today: "Today", + Yesterday: "Yesterday", + Last3Days: "Last 3 days", + Last7Days: "Last 7 days", + Last30Days: "Last 30 days", + Last90Days: "Last 90 days", + Last180Days: "Last 180 days", + LastYear: "Last year" +}; +export const TimeRange = Object.freeze(timeRange); \ No newline at end of file diff --git a/src/lib/helpers/types/conversationTypes.js b/src/lib/helpers/types/conversationTypes.js index 23862c00..cceb1505 100644 --- a/src/lib/helpers/types/conversationTypes.js +++ b/src/lib/helpers/types/conversationTypes.js @@ -14,6 +14,8 @@ * @property {boolean?} [isLoadLatestStates] * @property {import('$commonTypes').KeyValuePair[]} [states] - The conversation status. * @property {string[]} [tags] - The tags. + * @property {string?} [startTime] + * @property {string?} [endTime] */ /** @@ -41,6 +43,8 @@ * @property {number?} [convLimit] - The conversation limit. * @property {boolean?} [preload] - Whether it is preloading or not. * @property {string[]?} [agentIds] + * @property {string?} [startTime] + * @property {string?} [endTime] */ @@ -307,6 +311,7 @@ IRichContent.prototype.language; * @property {string?} [status] * @property {UserStateDetailModel[]} states * @property {string[]} tags + * @property {string?} [timeRange] */ /** diff --git a/src/lib/helpers/types/instructTypes.js b/src/lib/helpers/types/instructTypes.js index 9538dec6..102936a7 100644 --- a/src/lib/helpers/types/instructTypes.js +++ b/src/lib/helpers/types/instructTypes.js @@ -23,6 +23,8 @@ * @property {string[]?} [providers] * @property {string[]?} [models] * @property {string[]?} [templateNames] + * @property {string?} [startTime] + * @property {string?} [endTime] * @property {{key: string, value: string}[]?} [states] */ @@ -49,6 +51,8 @@ * @property {number?} [logLimit] - The log limit. * @property {boolean?} [preload] - Whether it is preloading or not. * @property {string[]?} [agentIds] + * @property {string?} [startTime] + * @property {string?} [endTime] */ export default {}; \ No newline at end of file diff --git a/src/lib/helpers/utils/common.js b/src/lib/helpers/utils/common.js index cf22a03b..5b263aa7 100644 --- a/src/lib/helpers/utils/common.js +++ b/src/lib/helpers/utils/common.js @@ -1,4 +1,7 @@ import { goto } from '$app/navigation'; +import moment from 'moment'; +import { TIME_RANGE_OPTIONS } from '../constants'; +import { TimeRange } from '../enums'; export function range(size = 3, startAt = 0) { return [...Array(size).keys()].map((i) => i + startAt); @@ -155,4 +158,61 @@ export function splitTextByCase(str) { let text = words.map(word => word.toLowerCase()).join(' '); text = text.charAt(0).toUpperCase() + text.slice(1); return text; +} + +/** + * @param {string} timeRange + * @returns {{ startTime: string | null, endTime: string | null }} + */ +export function convertTimeRange(timeRange) { + let ret = { startTime: null, endTime: null }; + + if (!timeRange) { + return ret; + } + + const found = TIME_RANGE_OPTIONS.find(x => x.value === timeRange); + if (!found) { + return ret; + } + + switch (found.value) { + case TimeRange.Last15Minutes: + case TimeRange.Last30Minutes: + case TimeRange.Last1Hour: + case TimeRange.Last3Hours: + case TimeRange.Last12Hours: + case TimeRange.Last3Days: + case TimeRange.Last7Days: + case TimeRange.Last30Days: + case TimeRange.Last90Days: + case TimeRange.Last180Days: + case TimeRange.LastYear: + ret = { + ...ret, + // @ts-ignore + startTime: moment().subtract(found.qty, found.unit).utc().format() + }; + break; + case TimeRange.Today: + ret = { + ...ret, + // @ts-ignore + startTime: moment().startOf('day').utc().format() + }; + break; + case TimeRange.Yesterday: + ret = { + ...ret, + // @ts-ignore + startTime: moment().subtract(1, 'days').startOf('day').utc().format(), + // @ts-ignore + endTime: moment().subtract(1, 'days').endOf('day').utc().format() + }; + break; + default: + break; + } + + return ret; } \ No newline at end of file diff --git a/src/routes/page/conversation/+page.svelte b/src/routes/page/conversation/+page.svelte index 9c69abec..6c641cf0 100644 --- a/src/routes/page/conversation/+page.svelte +++ b/src/routes/page/conversation/+page.svelte @@ -22,11 +22,15 @@ import { getAgentOptions } from '$lib/services/agent-service'; import { getConversations, deleteConversation, getConversationStateSearchKeys } from '$lib/services/conversation-service.js'; import { utcToLocal } from '$lib/helpers/datetime'; - import { ConversationChannel } from '$lib/helpers/enums'; + import { ConversationChannel, TimeRange } from '$lib/helpers/enums'; + import { TIME_RANGE_OPTIONS } from '$lib/helpers/constants'; import { getPagingQueryParams, setUrlQueryParams, - goToUrl + goToUrl, + + convertTimeRange + } from '$lib/helpers/utils/common'; @@ -70,6 +74,17 @@ { value: k.toLowerCase(), label: v } )); + const timeRangeOptions = TIME_RANGE_OPTIONS.map(x => ({ + label: x.label, + value: x.value + })); + + /** @type {{ startTime: string | null, endTime: string | null }} */ + let innerTimeRange = { + startTime: null, + endTime: null + }; + /** @type {import('$conversationTypes').ConversationSearchOption} */ let searchOption = { agentId: null, @@ -77,6 +92,7 @@ channel: null, status: null, taskId: null, + timeRange: TimeRange.Last3Hours, states: [], tags: [] }; @@ -91,9 +107,12 @@ page: $page.url.searchParams.get("page"), pageSize: $page.url.searchParams.get("pageSize") }, { defaultPageSize: pageSize }); + innerTimeRange = convertTimeRange(searchOption.timeRange || ''); filter = { ...filter, + startTime: innerTimeRange.startTime, + endTime: innerTimeRange.endTime, pager: { ...filter.pager, page: pageNum, @@ -103,21 +122,11 @@ isLoading = true; try { - const [agents] = await Promise.all([ + await Promise.all([ loadAgentOptions(), - loadSearchOption() + loadSearchOption(), + loadConversations() ]); - - searchOption = { - ...searchOption, - agentIds: agents?.length > 0 ? [agents[0].value] : [] - }; - filter = { - ...filter, - agentIds: searchOption.agentIds - }; - - await loadConversations(); } catch (error) { console.error('Error loading data:', error); } finally { @@ -282,6 +291,8 @@ function refreshFilter() { const searchStates = getSearchStates(); + innerTimeRange = convertTimeRange(searchOption.timeRange || ''); + filter = { ...filter, agentId: searchOption.agentId, @@ -290,7 +301,9 @@ status: searchOption.status, taskId: searchOption.taskId, states: searchStates, - tags: searchOption.tags + tags: searchOption.tags, + startTime: innerTimeRange.startTime, + endTime: innerTimeRange.endTime }; } @@ -377,6 +390,11 @@ ...searchOption, tags: e.target.value?.length > 0 ? [e.target.value] : [] }; + } else if (type === 'timeRange') { + searchOption = { + ...searchOption, + timeRange: selectedValues.length > 0 ? selectedValues[0] : null + }; } } @@ -386,7 +404,9 @@ getConversationStateSearchKeys({ query: query, keyLimit: 20, - agentIds: searchOption.agentId ? [searchOption.agentId] : null + agentIds: searchOption.agentId ? [searchOption.agentId] : null, + startTime: innerTimeRange.startTime, + endTime: innerTimeRange.endTime }).then((/** @type {any[]} */ res) => { resolve(res || []); }).catch(() => resolve([])); @@ -448,7 +468,7 @@ on:select={e => changeOption(e, 'agent')} /> - + changeOption(e, 'timeRange')} + /> +