Skip to content

Conversation

@yileicn
Copy link
Member

@yileicn yileicn commented Jan 30, 2026

PR Type

Enhancement


Description

  • Create reusable TimeRangePicker component with tabbed interface

    • Supports both relative (preset) and custom date range selection
    • Floating dropdown with tab-based UI for better UX
  • Replace SpecificDay enum with custom date range support

    • Removes single-day limitation, enables date range selection
    • Uses startDate and endDate fields instead of specificDate
  • Defer query execution on time range selection

    • Users must click Filter button to execute queries
    • Prevents immediate API calls during date picker interaction
  • Integrate TimeRangePicker into conversation and instruction log pages

    • Replaces previous Select dropdown with new component
    • Removes conditional date input for specific day selection

Diagram Walkthrough

flowchart LR
  A["TimeRangePicker Component"] -->|"Relative Tab"| B["Preset Time Ranges"]
  A -->|"Custom Tab"| C["Date Range Picker"]
  C -->|"startDate + endDate"| D["Custom Date Range"]
  B -->|"Emit Change Event"| E["Update searchOption"]
  D -->|"Emit Change Event"| E
  E -->|"User clicks Filter"| F["Execute Query"]
Loading

File Walkthrough

Relevant files
Enhancement
TimeRangePicker.svelte
New TimeRangePicker component with tabbed interface           

src/lib/common/shared/TimeRangePicker.svelte

  • New reusable component for time range selection with tabbed interface
  • Implements relative tab with preset time range options
  • Implements custom tab with date range picker (From/To dates)
  • Emits change event with timeRange, startDate, and endDate
  • Uses clickoutsideDirective to close picker when clicking outside
+229/-0 
+page.svelte
Replace Select with TimeRangePicker, defer query execution

src/routes/page/conversation/+page.svelte

  • Import and integrate TimeRangePicker component replacing Select
    dropdown
  • Update searchOption to use startDate and endDate instead of
    specificDate
  • Remove getTodayStr() function (moved to component)
  • Remove timeRangeOptions mapping (moved to component)
  • Update convertTimeRange() calls to pass startDate and endDate
    parameters
  • Remove conditional date input for SpecificDay time range
  • Defer query execution by removing immediate trigger on time range
    change
+16/-35 
+page.svelte
Replace Select with TimeRangePicker, defer query execution

src/routes/page/instruction/log/+page.svelte

  • Import and integrate TimeRangePicker component replacing Select
    dropdown
  • Update searchOption to use startDate and endDate instead of
    specificDate
  • Remove getTodayStr() and timeRangeOptions (moved to component)
  • Update convertTimeRange() calls to pass startDate and endDate
    parameters
  • Remove conditional date input for SpecificDay time range
  • Defer query execution by removing immediate trigger on time range
    change
+17/-36 
common.js
Update convertTimeRange to support date ranges                     

src/lib/helpers/utils/common.js

  • Import CUSTOM_DATE_RANGE constant
  • Update convertTimeRange() function signature to accept startDate and
    endDate instead of specificDate
  • Replace TimeRange.SpecificDay case with CUSTOM_DATE_RANGE case
  • Support date range by using endDate (defaults to startDate if not
    provided)
  • Update JSDoc comments to reflect new parameters
+9/-7     
Configuration changes
constants.js
Add CUSTOM_DATE_RANGE constant, remove SpecificDay             

src/lib/helpers/constants.js

  • Add CUSTOM_DATE_RANGE constant for custom date range identifier
  • Remove SpecificDay option from TIME_RANGE_OPTIONS array
  • Custom date range is now handled separately from preset options
+3/-1     
enums.js
Remove SpecificDay from TimeRange enum                                     

src/lib/helpers/enums.js

  • Remove SpecificDay enum value from TimeRange object
  • Simplifies time range enum to only include preset relative ranges
+0/-1     
Documentation
conversationTypes.js
Update ConversationSearchOption type documentation             

src/lib/helpers/types/conversationTypes.js

  • Update ConversationSearchOption JSDoc to replace specificDate with
    startDate and endDate
  • Document that endDate defaults to startDate if not provided
  • Clarify that custom date range uses CUSTOM_DATE_RANGE identifier
+2/-1     

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 30, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Date range validation: The new custom date range confirm flow does not validate missing/invalid dates or the
boundary case where endDate is earlier than startDate, potentially producing incorrect
filters without user feedback.

Referred Code
on:click={(e) => {
	e.preventDefault();
	e.stopPropagation();
	if (searchOption.startDate) {
		// If endDate is not provided, default to startDate
		if (!searchOption.endDate) {
			searchOption.endDate = searchOption.startDate;
		}
		// Force reactivity by reassigning the object
		searchOption = {
			...searchOption,
			timeRange: CUSTOM_DATE_RANGE
		};
	}
	showDatePicker = false;
	refreshFilter();
	initFilterPager();
	getPagedConversations();
}}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated date inputs: convertTimeRange() accepts startDate/endDate and silently returns null times when dates
are invalid or inconsistent (e.g., endDate < startDate), lacking explicit
validation/sanitization for externally-controlled inputs.

Referred Code
export function convertTimeRange(timeRange, startDate, endDate) {
    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:


 ... (clipped 37 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 30, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle custom date before lookup

In convertTimeRange, move the CUSTOM_DATE_RANGE check before the
TIME_RANGE_OPTIONS lookup to ensure custom date ranges are processed correctly.

src/lib/helpers/utils/common.js [199-262]

 export function convertTimeRange(timeRange, startDate, endDate) {
     let ret = { startTime: null, endTime: null };
+
+    // Handle custom range first
+    if (timeRange === CUSTOM_DATE_RANGE) {
+        if (startDate && moment(startDate).isValid()) {
+            const endDateToUse = endDate && moment(endDate).isValid() ? endDate : startDate;
+            return {
+                startTime: moment(startDate).startOf('day').utc().format(),
+                endTime: moment(endDateToUse).endOf('day').utc().format()
+            };
+        }
+        return ret;
+    }
 
     if (!timeRange) {
         return ret;
     }
 
     const found = TIME_RANGE_OPTIONS.find(x => x.value === timeRange);
     if (!found) {
         return ret;
     }
     ...
-    switch (timeRange) {
-    ...
-        case CUSTOM_DATE_RANGE:
-            if (startDate && moment(startDate).isValid()) {
-                const endDateToUse = endDate && moment(endDate).isValid() ? endDate : startDate;
-                ret = {
-                    ...ret,
-                    startTime: moment(startDate).startOf('day').utc().format(),
-                    endTime: moment(endDateToUse).endOf('day').utc().format()
-                };
-            }
-            break;
-    ...
-    }
-
-    return ret;
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 10

__

Why: This suggestion correctly identifies a critical bug where the logic for handling custom date ranges would never be executed, rendering the new feature non-functional.

High
Validate and correct invalid date ranges

In the custom date range 'Confirm' button handler, add logic to swap the start
and end dates if the user selects a start date that is after the end date.

src/routes/page/conversation/+page.svelte [703-721]

 on:click={(e) => {
     e.preventDefault();
     e.stopPropagation();
     if (searchOption.startDate) {
         // If endDate is not provided, default to startDate
         if (!searchOption.endDate) {
             searchOption.endDate = searchOption.startDate;
         }
+
+        // Ensure startDate is not after endDate by swapping them if needed
+        if (new Date(searchOption.startDate) > new Date(searchOption.endDate)) {
+            [searchOption.startDate, searchOption.endDate] = [searchOption.endDate, searchOption.startDate];
+        }
+
         // Force reactivity by reassigning the object
         searchOption = {
             ...searchOption,
             timeRange: CUSTOM_DATE_RANGE
         };
     }
     showDatePicker = false;
     refreshFilter();
     initFilterPager();
     getPagedConversations();
 }}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential user error where the start date is after the end date and proposes a sensible fix by swapping them, which improves robustness.

Low
High-level
Extract date picker into reusable component

The new date range picker's UI and logic are duplicated in
conversation/+page.svelte and instruction/log/+page.svelte. This should be
extracted into a reusable Svelte component to improve maintainability.

Examples:

src/routes/page/conversation/+page.svelte [582-730]
					<Col lg="2" class="position-relative">
						<button
							type="button"
							class="form-control text-start d-flex align-items-center justify-content-between"
							on:click={() => {
								showDatePicker = !showDatePicker;
								if (showDatePicker) {
									// If custom date is selected, switch to custom tab; otherwise use relative tab
									datePickerTab = searchOption.timeRange === CUSTOM_DATE_RANGE ? 'custom' : 'relative';
								}

 ... (clipped 139 lines)
src/routes/page/instruction/log/+page.svelte [447-591]
					<Col lg="2" class="position-relative">
						<button
							type="button"
							class="form-control text-start d-flex align-items-center justify-content-between"
							on:click={() => {
								showDatePicker = !showDatePicker;
								if (showDatePicker) {
									// If custom date is selected, switch to custom tab; otherwise use relative tab
									datePickerTab = searchOption.timeRange === CUSTOM_DATE_RANGE ? 'custom' : 'relative';
								}

 ... (clipped 135 lines)

Solution Walkthrough:

Before:

// In conversation/+page.svelte AND instruction/log/+page.svelte

// --- SCRIPT SECTION ---
let showDatePicker = false;
let datePickerTab = 'relative';
let timeRangeDisplayText = '';
// ... other state ...

const getYesterdayStr = () => { ... };
const formatDateForDisplay = (dateStr) => { ... };

$: {
  // logic to set timeRangeDisplayText based on searchOption
}

// --- MARKUP SECTION ---
<button on:click={() => showDatePicker = !showDatePicker}>...</button>
{#if showDatePicker}
  <div use:clickoutsideDirective on:clickoutside>
    <!-- Tab navigation for Relative/Custom -->
    <!-- Tab content with relative options or custom date inputs -->
  </div>
{/if}

After:

// In new file: src/lib/components/DateRangePicker.svelte
<script>
  // All logic for date picking, tabs, display text, etc.
  // Dispatch events on selection.
</script>

<!-- Generic date picker UI -->
<button on:click={togglePicker}>...</button>
{#if showPicker}
  <div>
    <!-- Tabs, inputs, and buttons -->
  </div>
{/if}

// In conversation/+page.svelte AND instruction/log/+page.svelte
<script>
  import DateRangePicker from '$lib/components/DateRangePicker.svelte';
  // ...
  function handleDateChange() {
    // refresh data
  }
</script>

<DateRangePicker
  bind:timeRange={searchOption.timeRange}
  bind:startDate={searchOption.startDate}
  bind:endDate={searchOption.endDate}
  on:change={handleDateChange}
/>
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies significant UI and logic duplication for the new date picker in conversation/+page.svelte and instruction/log/+page.svelte, and abstracting this into a reusable component is a crucial improvement for maintainability.

High
General
Trigger reactivity on preset select

In the preset time range on:click handler, reassign the entire searchOption
object instead of mutating its properties directly to ensure Svelte's reactivity
is triggered.

src/routes/page/conversation/+page.svelte [647-665]

 {#each presetTimeRangeOptions as option}
   <button
     type="button"
     class="btn btn-sm btn-outline-secondary text-start {searchOption.timeRange === option.value ? 'active' : ''}"
     on:click={(e) => {
       e.preventDefault();
       e.stopPropagation();
-      searchOption.timeRange = option.value;
-      searchOption.startDate = '';
-      searchOption.endDate = '';
+      searchOption = {
+        ...searchOption,
+        timeRange: option.value,
+        startDate: '',
+        endDate: ''
+      };
       showDatePicker = false;
       refreshFilter();
       initFilterPager();
       getPagedConversations();
     }}
   >
     {option.label}
   </button>
 {/each}
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that direct mutation of searchOption properties will not trigger Svelte's reactivity, leading to a stale UI display for the selected time range.

Medium
  • Update

Remove immediate query trigger when selecting time range. Users must click Filter button to execute query.
@yileicn
Copy link
Member Author

yileicn commented Jan 30, 2026

/describe /compliant /improve /review

@qodo-code-review
Copy link

PR Description updated to latest commit (f150584)

@yileicn yileicn changed the title feat: add custom date range picker with floating tabbed interface feat: Create reusable TimeRangePicker component with tabbed interface Jan 30, 2026
@iceljc iceljc merged commit b74ab30 into SciSharp:main Jan 30, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants