diff --git a/packages/ui/src/components/base/TimeFramePicker.vue b/packages/ui/src/components/base/TimeFramePicker.vue new file mode 100644 index 0000000000..38d6b1726d --- /dev/null +++ b/packages/ui/src/components/base/TimeFramePicker.vue @@ -0,0 +1,946 @@ + + + diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json index 5dfe375f43..ca1e6e95db 100644 --- a/packages/ui/src/locales/en-US/index.json +++ b/packages/ui/src/locales/en-US/index.json @@ -4301,6 +4301,87 @@ "tag.loader.waterfall": { "defaultMessage": "Waterfall" }, + "time-frame-picker.apply": { + "defaultMessage": "Apply" + }, + "time-frame-picker.cancel": { + "defaultMessage": "Cancel" + }, + "time-frame-picker.clear-range": { + "defaultMessage": "Clear" + }, + "time-frame-picker.custom-range": { + "defaultMessage": "Custom fixed date range..." + }, + "time-frame-picker.decrease-amount": { + "defaultMessage": "Decrease timeframe amount" + }, + "time-frame-picker.empty-range": { + "defaultMessage": "No date range selected." + }, + "time-frame-picker.increase-amount": { + "defaultMessage": "Increase timeframe amount" + }, + "time-frame-picker.last-timeframe": { + "defaultMessage": "In the last {amount} {unit, select, hours {{amount, plural, one {hour} other {hours}}} days {{amount, plural, one {day} other {days}}} weeks {{amount, plural, one {week} other {weeks}}} months {{amount, plural, one {month} other {months}}} other {days}}" + }, + "time-frame-picker.last-timeframe-prefix": { + "defaultMessage": "In the last" + }, + "time-frame-picker.option.all-time": { + "defaultMessage": "All time" + }, + "time-frame-picker.option.last-14-days": { + "defaultMessage": "Last 14 days" + }, + "time-frame-picker.option.last-180-days": { + "defaultMessage": "Last 180 days" + }, + "time-frame-picker.option.last-30-days": { + "defaultMessage": "Last 30 days" + }, + "time-frame-picker.option.last-7-days": { + "defaultMessage": "Last 7 days" + }, + "time-frame-picker.option.last-90-days": { + "defaultMessage": "Last 90 days" + }, + "time-frame-picker.option.today": { + "defaultMessage": "Today" + }, + "time-frame-picker.option.year-to-date": { + "defaultMessage": "Year to date" + }, + "time-frame-picker.option.yesterday": { + "defaultMessage": "Yesterday" + }, + "time-frame-picker.select-timeframe": { + "defaultMessage": "Select timeframe" + }, + "time-frame-picker.selected-range": { + "defaultMessage": "Selected" + }, + "time-frame-picker.selecting-range": { + "defaultMessage": "Selecting" + }, + "time-frame-picker.timeframe-amount": { + "defaultMessage": "Timeframe amount" + }, + "time-frame-picker.timeframe-unit": { + "defaultMessage": "Timeframe unit" + }, + "time-frame-picker.unit.days": { + "defaultMessage": "days" + }, + "time-frame-picker.unit.hours": { + "defaultMessage": "hours" + }, + "time-frame-picker.unit.months": { + "defaultMessage": "months" + }, + "time-frame-picker.unit.weeks": { + "defaultMessage": "weeks" + }, "ui.component.unsaved-changes-popup.body": { "defaultMessage": "You have unsaved changes." }, diff --git a/packages/ui/src/stories/base/TimeFramePicker.stories.ts b/packages/ui/src/stories/base/TimeFramePicker.stories.ts new file mode 100644 index 0000000000..7c511faf3b --- /dev/null +++ b/packages/ui/src/stories/base/TimeFramePicker.stories.ts @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { ref } from 'vue' + +import TimeFramePicker, { + type TimeFrameLastUnit, + type TimeFrameMode, + type TimeFramePreset, +} from '../../components/base/TimeFramePicker.vue' + +const meta = { + title: 'Base/TimeFramePicker', + component: TimeFramePicker, + parameters: { + layout: 'padded', + }, + decorators: [ + (story) => ({ + components: { story }, + template: '
', + }), + ], +} satisfies Meta + +export default meta +type Story = StoryObj + +function renderPicker(initial: { + mode?: TimeFrameMode + preset?: TimeFramePreset + lastAmount?: number + lastUnit?: TimeFrameLastUnit + customStartDate?: string + customEndDate?: string +} = {}) { + return () => ({ + components: { TimeFramePicker }, + setup() { + const mode = ref(initial.mode ?? 'preset') + const preset = ref(initial.preset ?? 'last_30_days') + const lastAmount = ref(initial.lastAmount ?? 1) + const lastUnit = ref(initial.lastUnit ?? 'days') + const customStartDate = ref(initial.customStartDate ?? '2026-04-23') + const customEndDate = ref(initial.customEndDate ?? '2026-05-22') + + return { + customEndDate, + customStartDate, + lastAmount, + lastUnit, + mode, + preset, + } + }, + template: /* html */ ` + + `, + }) +} + +export const Preset: Story = { + render: renderPicker(), +} + +export const LastTimeframe: Story = { + render: renderPicker({ + mode: 'last', + lastAmount: 12, + lastUnit: 'hours', + }), +} + +export const CustomRange: Story = { + render: renderPicker({ + mode: 'custom_range', + customStartDate: '2026-04-23', + customEndDate: '2026-05-22', + }), +}