mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-04 21:11:08 +02:00
Extend time range (contributor submission) (#2484)
* added new options for time range; removed duplicated code * refactor + remove unused code --------- Co-authored-by: Zoltan Szabo <zoltan.szabo@eaudeweb.ro>
This commit is contained in:
@@ -1,453 +0,0 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import { DocumentSet, Tag, ValidSources } from "@/lib/types";
|
|
||||||
import { SourceMetadata } from "@/lib/search/interfaces";
|
|
||||||
import {
|
|
||||||
FiBook,
|
|
||||||
FiBookmark,
|
|
||||||
FiCalendar,
|
|
||||||
FiFilter,
|
|
||||||
FiMap,
|
|
||||||
FiTag,
|
|
||||||
FiX,
|
|
||||||
} from "react-icons/fi";
|
|
||||||
import { DateRangePickerValue } from "@tremor/react";
|
|
||||||
import { listSourceMetadata } from "@/lib/sources";
|
|
||||||
import { SourceIcon } from "@/components/SourceIcon";
|
|
||||||
import { BasicClickable } from "@/components/BasicClickable";
|
|
||||||
import { ControlledPopup, DefaultDropdownElement } from "@/components/Dropdown";
|
|
||||||
import { getXDaysAgo } from "@/lib/dateUtils";
|
|
||||||
import { SourceSelectorProps } from "@/components/search/filtering/Filters";
|
|
||||||
import { containsObject, objectsAreEquivalent } from "@/lib/contains";
|
|
||||||
|
|
||||||
enum FilterType {
|
|
||||||
Source = "Source",
|
|
||||||
KnowledgeSet = "Knowledge Set",
|
|
||||||
TimeRange = "Time Range",
|
|
||||||
Tag = "Tag",
|
|
||||||
}
|
|
||||||
|
|
||||||
function SelectedBubble({
|
|
||||||
children,
|
|
||||||
onClick,
|
|
||||||
}: {
|
|
||||||
children: string | JSX.Element;
|
|
||||||
onClick: () => void;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"flex text-xs cursor-pointer items-center border border-border " +
|
|
||||||
"py-1 rounded-lg px-2 w-fit select-none hover:bg-hover"
|
|
||||||
}
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
<FiX className="ml-2" size={14} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SelectFilterType({
|
|
||||||
onSelect,
|
|
||||||
hasSources,
|
|
||||||
hasKnowledgeSets,
|
|
||||||
hasTags,
|
|
||||||
}: {
|
|
||||||
onSelect: (filterType: FilterType) => void;
|
|
||||||
hasSources: boolean;
|
|
||||||
hasKnowledgeSets: boolean;
|
|
||||||
hasTags: boolean;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="w-64">
|
|
||||||
{hasSources && (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={FilterType.Source}
|
|
||||||
name={FilterType.Source}
|
|
||||||
icon={FiMap}
|
|
||||||
onSelect={() => onSelect(FilterType.Source)}
|
|
||||||
isSelected={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasKnowledgeSets && (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={FilterType.KnowledgeSet}
|
|
||||||
name={FilterType.KnowledgeSet}
|
|
||||||
icon={FiBook}
|
|
||||||
onSelect={() => onSelect(FilterType.KnowledgeSet)}
|
|
||||||
isSelected={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasTags && (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={FilterType.Tag}
|
|
||||||
name={FilterType.Tag}
|
|
||||||
icon={FiTag}
|
|
||||||
onSelect={() => onSelect(FilterType.Tag)}
|
|
||||||
isSelected={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={FilterType.TimeRange}
|
|
||||||
name={FilterType.TimeRange}
|
|
||||||
icon={FiCalendar}
|
|
||||||
onSelect={() => onSelect(FilterType.TimeRange)}
|
|
||||||
isSelected={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SourcesSection({
|
|
||||||
sources,
|
|
||||||
selectedSources,
|
|
||||||
onSelect,
|
|
||||||
}: {
|
|
||||||
sources: SourceMetadata[];
|
|
||||||
selectedSources: string[];
|
|
||||||
onSelect: (source: SourceMetadata) => void;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="w-64">
|
|
||||||
{sources.map((source) => (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={source.internalName}
|
|
||||||
name={source.displayName}
|
|
||||||
icon={source.icon}
|
|
||||||
onSelect={() => onSelect(source)}
|
|
||||||
isSelected={selectedSources.includes(source.internalName)}
|
|
||||||
includeCheckbox
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function KnowledgeSetsSection({
|
|
||||||
documentSets,
|
|
||||||
selectedDocumentSets,
|
|
||||||
onSelect,
|
|
||||||
}: {
|
|
||||||
documentSets: DocumentSet[];
|
|
||||||
selectedDocumentSets: string[];
|
|
||||||
onSelect: (documentSetName: string) => void;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="w-64">
|
|
||||||
{documentSets.map((documentSet) => (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={documentSet.name}
|
|
||||||
name={documentSet.name}
|
|
||||||
icon={FiBookmark}
|
|
||||||
onSelect={() => onSelect(documentSet.name)}
|
|
||||||
isSelected={selectedDocumentSets.includes(documentSet.name)}
|
|
||||||
includeCheckbox
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAST_30_DAYS = "Last 30 days";
|
|
||||||
const LAST_7_DAYS = "Last 7 days";
|
|
||||||
const TODAY = "Today";
|
|
||||||
|
|
||||||
function TimeRangeSection({
|
|
||||||
selectedTimeRange,
|
|
||||||
onSelect,
|
|
||||||
}: {
|
|
||||||
selectedTimeRange: string | null;
|
|
||||||
onSelect: (timeRange: DateRangePickerValue) => void;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="w-64">
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={LAST_30_DAYS}
|
|
||||||
name={LAST_30_DAYS}
|
|
||||||
onSelect={() =>
|
|
||||||
onSelect({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(30),
|
|
||||||
selectValue: LAST_30_DAYS,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={selectedTimeRange === LAST_30_DAYS}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={LAST_7_DAYS}
|
|
||||||
name={LAST_7_DAYS}
|
|
||||||
onSelect={() =>
|
|
||||||
onSelect({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(7),
|
|
||||||
selectValue: LAST_7_DAYS,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={selectedTimeRange === LAST_7_DAYS}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={TODAY}
|
|
||||||
name={TODAY}
|
|
||||||
onSelect={() =>
|
|
||||||
onSelect({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(1),
|
|
||||||
selectValue: TODAY,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={selectedTimeRange === TODAY}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TagsSection({
|
|
||||||
availableTags,
|
|
||||||
selectedTags,
|
|
||||||
onSelect,
|
|
||||||
}: {
|
|
||||||
availableTags: Tag[];
|
|
||||||
selectedTags: Tag[];
|
|
||||||
onSelect: (tag: Tag) => void;
|
|
||||||
}) {
|
|
||||||
const [filterValue, setFilterValue] = useState("");
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.focus();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filterValueLower = filterValue.toLowerCase();
|
|
||||||
const filteredTags = filterValueLower
|
|
||||||
? availableTags.filter(
|
|
||||||
(tags) =>
|
|
||||||
tags.tag_value.toLowerCase().startsWith(filterValueLower) ||
|
|
||||||
tags.tag_key.toLowerCase().startsWith(filterValueLower)
|
|
||||||
)
|
|
||||||
: availableTags;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-96">
|
|
||||||
<div className="max-h-48 overflow-y-auto">
|
|
||||||
{filteredTags.length > 0 ? (
|
|
||||||
filteredTags.map((tag) => (
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={tag.tag_key + tag.tag_value}
|
|
||||||
name={
|
|
||||||
<div className="max-w-full break-all line-clamp-1 text-ellipsis">
|
|
||||||
{tag.tag_key}
|
|
||||||
<b>=</b>
|
|
||||||
{tag.tag_value}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
onSelect={() => onSelect(tag)}
|
|
||||||
isSelected={selectedTags.includes(tag)}
|
|
||||||
includeCheckbox
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div className="text-sm px-2 py-2">No matching tags found</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mx-2 mb-2 pt-2 border-t border-border">
|
|
||||||
<input
|
|
||||||
ref={inputRef}
|
|
||||||
className="w-full border border-border py-0.5 px-2 rounded text-sm h-8 "
|
|
||||||
placeholder="Find a tag"
|
|
||||||
value={filterValue}
|
|
||||||
onChange={(event) => setFilterValue(event.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ChatFilters({
|
|
||||||
timeRange,
|
|
||||||
setTimeRange,
|
|
||||||
selectedSources,
|
|
||||||
setSelectedSources,
|
|
||||||
selectedDocumentSets,
|
|
||||||
setSelectedDocumentSets,
|
|
||||||
selectedTags,
|
|
||||||
setSelectedTags,
|
|
||||||
availableDocumentSets,
|
|
||||||
existingSources,
|
|
||||||
availableTags,
|
|
||||||
}: SourceSelectorProps) {
|
|
||||||
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
||||||
const handleFiltersToggle = (value: boolean) => {
|
|
||||||
setSelectedFilterType(null);
|
|
||||||
setFiltersOpen(value);
|
|
||||||
};
|
|
||||||
const [selectedFilterType, setSelectedFilterType] =
|
|
||||||
useState<FilterType | null>(null);
|
|
||||||
|
|
||||||
const handleSourceSelect = (source: SourceMetadata) => {
|
|
||||||
setSelectedSources((prev: SourceMetadata[]) => {
|
|
||||||
const prevSourceNames = prev.map((source) => source.internalName);
|
|
||||||
if (prevSourceNames.includes(source.internalName)) {
|
|
||||||
return prev.filter((s) => s.internalName !== source.internalName);
|
|
||||||
} else {
|
|
||||||
return [...prev, source];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDocumentSetSelect = (documentSetName: string) => {
|
|
||||||
setSelectedDocumentSets((prev: string[]) => {
|
|
||||||
if (prev.includes(documentSetName)) {
|
|
||||||
return prev.filter((s) => s !== documentSetName);
|
|
||||||
} else {
|
|
||||||
return [...prev, documentSetName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTagToggle = (tag: Tag) => {
|
|
||||||
setSelectedTags((prev) => {
|
|
||||||
if (containsObject(prev, tag)) {
|
|
||||||
return prev.filter((t) => !objectsAreEquivalent(t, tag));
|
|
||||||
} else {
|
|
||||||
return [...prev, tag];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const allSources = listSourceMetadata();
|
|
||||||
const availableSources = allSources.filter((source) =>
|
|
||||||
existingSources.includes(source.internalName)
|
|
||||||
);
|
|
||||||
|
|
||||||
let popupDisplay = null;
|
|
||||||
if (selectedFilterType === FilterType.Source) {
|
|
||||||
popupDisplay = (
|
|
||||||
<SourcesSection
|
|
||||||
sources={availableSources}
|
|
||||||
selectedSources={selectedSources.map((source) => source.internalName)}
|
|
||||||
onSelect={handleSourceSelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (selectedFilterType === FilterType.KnowledgeSet) {
|
|
||||||
popupDisplay = (
|
|
||||||
<KnowledgeSetsSection
|
|
||||||
documentSets={availableDocumentSets}
|
|
||||||
selectedDocumentSets={selectedDocumentSets}
|
|
||||||
onSelect={handleDocumentSetSelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (selectedFilterType === FilterType.TimeRange) {
|
|
||||||
popupDisplay = (
|
|
||||||
<TimeRangeSection
|
|
||||||
selectedTimeRange={timeRange?.selectValue || null}
|
|
||||||
onSelect={(timeRange) => {
|
|
||||||
setTimeRange(timeRange);
|
|
||||||
handleFiltersToggle(!filtersOpen);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (selectedFilterType === FilterType.Tag) {
|
|
||||||
popupDisplay = (
|
|
||||||
<TagsSection
|
|
||||||
availableTags={availableTags}
|
|
||||||
selectedTags={selectedTags}
|
|
||||||
onSelect={handleTagToggle}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
popupDisplay = (
|
|
||||||
<SelectFilterType
|
|
||||||
onSelect={(filterType) => setSelectedFilterType(filterType)}
|
|
||||||
hasSources={availableSources.length > 0}
|
|
||||||
hasKnowledgeSets={availableDocumentSets.length > 0}
|
|
||||||
hasTags={availableTags.length > 0}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex">
|
|
||||||
<ControlledPopup
|
|
||||||
isOpen={filtersOpen}
|
|
||||||
setIsOpen={handleFiltersToggle}
|
|
||||||
popupContent={popupDisplay}
|
|
||||||
>
|
|
||||||
<div className="flex">
|
|
||||||
<BasicClickable onClick={() => handleFiltersToggle(!filtersOpen)}>
|
|
||||||
<div className="flex text-xs">
|
|
||||||
<FiFilter className="my-auto mr-1" /> Filter
|
|
||||||
</div>
|
|
||||||
</BasicClickable>
|
|
||||||
</div>
|
|
||||||
</ControlledPopup>
|
|
||||||
|
|
||||||
<div className="flex ml-4">
|
|
||||||
{((timeRange && timeRange.selectValue !== undefined) ||
|
|
||||||
selectedSources.length > 0 ||
|
|
||||||
selectedDocumentSets.length > 0) && (
|
|
||||||
<p className="text-xs my-auto mr-1">Currently applied:</p>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-wrap gap-x-2">
|
|
||||||
{timeRange && timeRange.selectValue && (
|
|
||||||
<SelectedBubble onClick={() => setTimeRange(null)}>
|
|
||||||
<div className="flex">{timeRange.selectValue}</div>
|
|
||||||
</SelectedBubble>
|
|
||||||
)}
|
|
||||||
{existingSources.length > 0 &&
|
|
||||||
selectedSources.map((source) => (
|
|
||||||
<SelectedBubble
|
|
||||||
key={source.internalName}
|
|
||||||
onClick={() => handleSourceSelect(source)}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<SourceIcon sourceType={source.internalName} iconSize={16} />
|
|
||||||
<span className="ml-2">{source.displayName}</span>
|
|
||||||
</>
|
|
||||||
</SelectedBubble>
|
|
||||||
))}
|
|
||||||
{selectedDocumentSets.length > 0 &&
|
|
||||||
selectedDocumentSets.map((documentSetName) => (
|
|
||||||
<SelectedBubble
|
|
||||||
key={documentSetName}
|
|
||||||
onClick={() => handleDocumentSetSelect(documentSetName)}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<FiBookmark />
|
|
||||||
</div>
|
|
||||||
<span className="ml-2">{documentSetName}</span>
|
|
||||||
</>
|
|
||||||
</SelectedBubble>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{selectedTags.length > 0 &&
|
|
||||||
selectedTags.map((tag) => (
|
|
||||||
<SelectedBubble
|
|
||||||
key={tag.tag_key + tag.tag_value}
|
|
||||||
onClick={() => handleTagToggle(tag)}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<FiTag />
|
|
||||||
</div>
|
|
||||||
<span className="ml-1 max-w-[100px] text-ellipsis line-clamp-1 break-all">
|
|
||||||
{tag.tag_key}
|
|
||||||
<b>=</b>
|
|
||||||
{tag.tag_value}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
</SelectedBubble>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
9
web/src/app/config/timeRange.tsx
Normal file
9
web/src/app/config/timeRange.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { getXDaysAgo, getXYearsAgo } from "@/lib/dateUtils";
|
||||||
|
|
||||||
|
export const timeRangeValues = [
|
||||||
|
{ label: "Last 2 years", value: getXYearsAgo(2) },
|
||||||
|
{ label: "Last year", value: getXYearsAgo(1) },
|
||||||
|
{ label: "Last 30 days", value: getXDaysAgo(30) },
|
||||||
|
{ label: "Last 7 days", value: getXDaysAgo(7) },
|
||||||
|
{ label: "Today", value: getXDaysAgo(1) },
|
||||||
|
];
|
32
web/src/components/filters/TimeRangeSelector.tsx
Normal file
32
web/src/components/filters/TimeRangeSelector.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { DefaultDropdownElement } from "../Dropdown";
|
||||||
|
export function TimeRangeSelector({
|
||||||
|
value,
|
||||||
|
onValueChange,
|
||||||
|
className,
|
||||||
|
timeRangeValues,
|
||||||
|
}: {
|
||||||
|
value: any;
|
||||||
|
onValueChange: any;
|
||||||
|
className: any;
|
||||||
|
|
||||||
|
timeRangeValues: { label: string; value: Date }[];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{timeRangeValues.map((timeRangeValue) => (
|
||||||
|
<DefaultDropdownElement
|
||||||
|
key={timeRangeValue.label}
|
||||||
|
name={timeRangeValue.label}
|
||||||
|
onSelect={() =>
|
||||||
|
onValueChange({
|
||||||
|
to: new Date(),
|
||||||
|
from: timeRangeValue.value,
|
||||||
|
selectValue: timeRangeValue.label,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isSelected={value?.selectValue === timeRangeValue.label}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@@ -1,11 +1,8 @@
|
|||||||
import { getXDaysAgo } from "@/lib/dateUtils";
|
|
||||||
import { DateRangePickerValue } from "@tremor/react";
|
import { DateRangePickerValue } from "@tremor/react";
|
||||||
import { FiCalendar, FiChevronDown, FiXCircle } from "react-icons/fi";
|
import { FiCalendar, FiChevronDown, FiXCircle } from "react-icons/fi";
|
||||||
import { CustomDropdown, DefaultDropdownElement } from "../Dropdown";
|
import { CustomDropdown } from "../Dropdown";
|
||||||
|
import { timeRangeValues } from "@/app/config/timeRange";
|
||||||
export const LAST_30_DAYS = "Last 30 days";
|
import { TimeRangeSelector } from "@/components/filters/TimeRangeSelector";
|
||||||
export const LAST_7_DAYS = "Last 7 days";
|
|
||||||
export const TODAY = "Today";
|
|
||||||
|
|
||||||
export function DateRangeSelector({
|
export function DateRangeSelector({
|
||||||
value,
|
value,
|
||||||
@@ -20,59 +17,23 @@ export function DateRangeSelector({
|
|||||||
<div>
|
<div>
|
||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
dropdown={
|
dropdown={
|
||||||
<div
|
<TimeRangeSelector
|
||||||
|
value={value}
|
||||||
className={`
|
className={`
|
||||||
border
|
border
|
||||||
border-border
|
border-border
|
||||||
bg-background
|
bg-background
|
||||||
rounded-lg
|
rounded-lg
|
||||||
flex
|
flex
|
||||||
flex-col
|
flex-col
|
||||||
w-64
|
w-64
|
||||||
max-h-96
|
max-h-96
|
||||||
overflow-y-auto
|
overflow-y-auto
|
||||||
flex
|
flex
|
||||||
overscroll-contain`}
|
overscroll-contain`}
|
||||||
>
|
timeRangeValues={timeRangeValues}
|
||||||
<DefaultDropdownElement
|
onValueChange={onValueChange}
|
||||||
key={LAST_30_DAYS}
|
/>
|
||||||
name={LAST_30_DAYS}
|
|
||||||
onSelect={() =>
|
|
||||||
onValueChange({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(30),
|
|
||||||
selectValue: LAST_30_DAYS,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={value?.selectValue === LAST_30_DAYS}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={LAST_7_DAYS}
|
|
||||||
name={LAST_7_DAYS}
|
|
||||||
onSelect={() =>
|
|
||||||
onValueChange({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(7),
|
|
||||||
selectValue: LAST_7_DAYS,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={value?.selectValue === LAST_7_DAYS}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DefaultDropdownElement
|
|
||||||
key={TODAY}
|
|
||||||
name={TODAY}
|
|
||||||
onSelect={() =>
|
|
||||||
onValueChange({
|
|
||||||
to: new Date(),
|
|
||||||
from: getXDaysAgo(1),
|
|
||||||
selectValue: TODAY,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
isSelected={value?.selectValue === TODAY}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
import {
|
import {
|
||||||
DanswerDocument,
|
DanswerDocument,
|
||||||
DocumentRelevance,
|
DocumentRelevance,
|
||||||
Relevance,
|
|
||||||
SearchDanswerDocument,
|
SearchDanswerDocument,
|
||||||
} from "@/lib/search/interfaces";
|
} from "@/lib/search/interfaces";
|
||||||
import { DocumentFeedbackBlock } from "./DocumentFeedbackBlock";
|
import { DocumentFeedbackBlock } from "./DocumentFeedbackBlock";
|
||||||
@@ -12,11 +11,10 @@ import { PopupSpec } from "../admin/connectors/Popup";
|
|||||||
import { DocumentUpdatedAtBadge } from "./DocumentUpdatedAtBadge";
|
import { DocumentUpdatedAtBadge } from "./DocumentUpdatedAtBadge";
|
||||||
import { SourceIcon } from "../SourceIcon";
|
import { SourceIcon } from "../SourceIcon";
|
||||||
import { MetadataBadge } from "../MetadataBadge";
|
import { MetadataBadge } from "../MetadataBadge";
|
||||||
import { BookIcon, CheckmarkIcon, LightBulbIcon, XIcon } from "../icons/icons";
|
import { BookIcon, LightBulbIcon } from "../icons/icons";
|
||||||
|
|
||||||
import { FaStar } from "react-icons/fa";
|
import { FaStar } from "react-icons/fa";
|
||||||
import { FiTag } from "react-icons/fi";
|
import { FiTag } from "react-icons/fi";
|
||||||
import { DISABLE_LLM_DOC_RELEVANCE } from "@/lib/constants";
|
|
||||||
import { SettingsContext } from "../settings/SettingsProvider";
|
import { SettingsContext } from "../settings/SettingsProvider";
|
||||||
import { CustomTooltip, TooltipGroup } from "../tooltip/CustomTooltip";
|
import { CustomTooltip, TooltipGroup } from "../tooltip/CustomTooltip";
|
||||||
import { WarningCircle } from "@phosphor-icons/react";
|
import { WarningCircle } from "@phosphor-icons/react";
|
||||||
|
@@ -5,6 +5,13 @@ export function getXDaysAgo(daysAgo: number) {
|
|||||||
return daysAgoDate;
|
return daysAgoDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getXYearsAgo(yearsAgo: number) {
|
||||||
|
const today = new Date();
|
||||||
|
const yearsAgoDate = new Date(today);
|
||||||
|
yearsAgoDate.setFullYear(yearsAgoDate.getFullYear() - yearsAgo);
|
||||||
|
return yearsAgoDate;
|
||||||
|
}
|
||||||
|
|
||||||
export const timestampToDateString = (timestamp: string) => {
|
export const timestampToDateString = (timestamp: string) => {
|
||||||
const date = new Date(timestamp);
|
const date = new Date(timestamp);
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
|
Reference in New Issue
Block a user