Skip to content

Commit

Permalink
Add Date picker (#237)
Browse files Browse the repository at this point in the history
* date picker added

* add use local or utc zone

* provisioning

* upd DATETIME format

* test updated

* update to dateTimeFormat

* Update CHANGELOG.md

---------

Co-authored-by: Mikhail Volkov <[email protected]>
  • Loading branch information
vitPinchuk and mikhail-vl authored Jan 20, 2025
1 parent 60d2949 commit 5e1c007
Show file tree
Hide file tree
Showing 15 changed files with 494 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Updated sticky header for Scenes dashboards (#230)
- Updated display favorites icon (#234)
- Added not supports variable type Alert message (#235)
- Added Date picker (#237)

## 3.6.0 (2024-10-24)

Expand Down
106 changes: 100 additions & 6 deletions provisioning/dashboards/dateTime.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"header": true,
"isUseLocalTime": false,
"minimizeDisplayMode": "dateTimePicker",
"minimizeOutputFormat": "date",
"minimizeOutputFormat": "dateTime",
"padding": 10,
"persistent": false,
"saveSelectedGroup": false,
Expand All @@ -89,7 +89,6 @@
"tabsInOrder": true,
"variable": "first"
},
"pluginVersion": "3.6.0",
"targets": [
{
"datasource": {
Expand All @@ -102,6 +101,86 @@
"title": "Variable: First - ISO string",
"type": "volkovlabs-variable-panel"
},
{
"datasource": {
"name": "Static",
"type": "marcusolsson-static-datasource",
"uid": "P1D2C73DC01F2359B"
},
"fieldConfig": {
"defaults": {
"custom": {
"thresholdsStyle": {
"mode": "color",
"thresholds": []
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 5,
"x": 5,
"y": 0
},
"id": 4,
"options": {
"alwaysVisibleFilter": false,
"autoScroll": false,
"collapsedByDefault": false,
"customValue": false,
"displayMode": "minimize",
"emptyValue": false,
"favorites": {
"enabled": false,
"storage": "browser"
},
"filter": false,
"groupSelection": false,
"header": true,
"isUseLocalTime": true,
"minimizeDisplayMode": "dateTimePicker",
"minimizeOutputFormat": "date",
"padding": 10,
"persistent": false,
"saveSelectedGroup": false,
"saveSelectedGroupKey": "",
"showGroupTotal": false,
"showLabel": false,
"showName": false,
"showResetButton": false,
"showTotal": false,
"statusSort": false,
"sticky": false,
"tabsInOrder": true,
"variable": "DateOnly"
},
"targets": [
{
"datasource": {
"type": "marcusolsson-static-datasource",
"uid": "P1D2C73DC01F2359B"
},
"refId": "A"
}
],
"title": "Variable: Date Only",
"type": "volkovlabs-variable-panel"
},
{
"datasource": {
"name": "Static",
Expand Down Expand Up @@ -170,7 +249,6 @@
"tabsInOrder": true,
"variable": "second"
},
"pluginVersion": "3.6.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -251,7 +329,6 @@
"tabsInOrder": true,
"variable": "third"
},
"pluginVersion": "3.6.0",
"targets": [
{
"datasource": {
Expand Down Expand Up @@ -285,7 +362,7 @@
"value": "2024-05-05T14:48:00.000Z"
}
],
"query": "2024-05-18T14:48:00.000Z",
"query": "2024-05-03T14:48:00.000Z",
"type": "textbox"
},
{
Expand All @@ -302,7 +379,7 @@
"value": "1722429030000"
}
],
"query": "1721305830000",
"query": "1720873830000",
"type": "textbox"
},
{
Expand All @@ -312,6 +389,23 @@
"options": [],
"query": "",
"type": "textbox"
},
{
"current": {
"text": "2025-01-03",
"value": "2025-01-03"
},
"label": "DateOnly",
"name": "DateOnly",
"options": [
{
"selected": true,
"text": "2025-01-03",
"value": "2025-01-03"
}
],
"query": "2025-01-03",
"type": "textbox"
}
]
},
Expand Down
25 changes: 25 additions & 0 deletions src/__mocks__/@grafana/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,29 @@ const DateTimePickerMock = ({ onChange, date, ...restProps }: any) => {

const DateTimePicker = jest.fn(DateTimePickerMock);

/**
* Mock DatePickerWithInput component
*/
const DatePickerWithInputMock = ({ onChange, value, ...restProps }: any) => {
return (
<input
data-testid={restProps['data-testid']}
value={value}
onChange={(event) => {
/**
* Check Date type handle
*/
const value = event.target.value === '2009-09-09' ? new Date(event.target.value) : event.target.value;
if (onChange) {
onChange(value);
}
}}
/>
);
};

const DatePickerWithInput = jest.fn(DatePickerWithInputMock);

/**
* Mock Select component
*/
Expand Down Expand Up @@ -83,11 +106,13 @@ beforeEach(() => {
Select.mockImplementation(SelectMock);
DateTimePicker.mockImplementation(DateTimePickerMock);
ToolbarButtonRow.mockImplementation(ToolbarButtonRowMock);
DatePickerWithInput.mockImplementation(DatePickerWithInputMock);
});

module.exports = {
...actual,
ToolbarButtonRow,
Select,
DateTimePicker,
DatePickerWithInput,
};
180 changes: 180 additions & 0 deletions src/components/DateSelector/DateSelector.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { dateTimeFormat } from '@grafana/data';
import { act, fireEvent, render, screen } from '@testing-library/react';
import { getJestSelectors } from '@volkovlabs/jest-selectors';
import React from 'react';

import { TEST_IDS } from '../../constants';
import { selectVariableValues } from '../../utils';
import { DateSelector } from './DateSelector';

/**
* Mock utils
*/
jest.mock('../../utils', () => ({
selectVariableValues: jest.fn(),
}));

/**
* Mock dateTimeFormat
*/
jest.mock('@grafana/data', () => ({
...jest.requireActual('@grafana/data'),
dateTimeFormat: jest.fn(),
}));

/**
* Persistent Storage Mock
*/
const persistentStorageMock = {
remove: jest.fn(),
};

/**
* Mock hooks
*/
jest.mock('../../hooks', () => ({
...jest.requireActual('../../hooks'),
usePersistentStorage: jest.fn(() => persistentStorageMock),
}));

/**
* Properties
*/
type Props = React.ComponentProps<typeof DateSelector>;

/**
* Date Selector
*/
describe('Date Selector', () => {
const defaultVariable = {
label: 'dateTS',
current: {
value: '2025-01-21',
},
};

/**
* Selectors
*/
const getSelectors = getJestSelectors(TEST_IDS.datePicker);
const selectors = getSelectors(screen);

/**
* Get Tested Component
*/
const getComponent = (props: Partial<Props>) => {
return <DateSelector variable={defaultVariable} panelEventBus={{} as any} {...(props as any)} />;
};

beforeEach(() => {
jest.mocked(selectVariableValues).mockClear();
// jest.mocked(dateTimeFormat).mockReturnValue((str) => str);
});

it('Should apply initial variable value from variable', () => {
render(
getComponent({
variable: defaultVariable as any,
})
);

expect(selectors.root()).toBeVisible();
expect(selectors.root()).toHaveValue('2025-01-21');
});

it('Should apply initial variable value from variable if value is empty', () => {
const variable = {
label: 'dateTimeTS',
current: {
value: '',
},
} as any;

render(
getComponent({
variable: variable,
})
);

expect(selectors.root()).toBeVisible();
expect(selectors.root()).toHaveValue('');
});

it('Should update variable value from string', async () => {
jest.mocked(dateTimeFormat).mockImplementationOnce((str) => str as string);

render(
getComponent({
variable: defaultVariable as any,
persistent: true,
})
);

expect(selectors.root()).toBeVisible();
expect(selectors.root()).toHaveValue('2025-01-21');

/**
* Change Date
*/
const date = new Date('2024-07-31 12:30:30');
await act(() => fireEvent.change(selectors.root(), { target: { value: date.toISOString() } }));

expect(selectVariableValues).toHaveBeenCalledWith({
values: [date.toISOString()],
runtimeVariable: defaultVariable,
panelEventBus: {},
});

expect(persistentStorageMock.remove).toHaveBeenCalled();
});

it('Should update variable value', async () => {
jest.mocked(dateTimeFormat).mockImplementationOnce((str) => str as string);

render(
getComponent({
variable: defaultVariable as any,
persistent: true,
})
);

expect(selectors.root()).toBeVisible();
expect(selectors.root()).toHaveValue('2025-01-21');

/**
* Change Date
*/
const date = '2009-09-09';
await act(() => fireEvent.change(selectors.root(), { target: { value: date } }));

expect(selectVariableValues).toHaveBeenCalledWith(
expect.objectContaining({
runtimeVariable: defaultVariable,
panelEventBus: {},
})
);

expect(persistentStorageMock.remove).toHaveBeenCalled();
});

it('Should update variable value in local time', async () => {
render(
getComponent({
variable: defaultVariable as any,
persistent: true,
isUseLocalTime: true,
})
);

expect(selectors.root()).toBeVisible();
expect(selectors.root()).toHaveValue('2025-01-21');

/**
* Change Date
*/
const date = '2009-09-09';
await act(() => fireEvent.change(selectors.root(), { target: { value: date } }));

expect(dateTimeFormat).toHaveBeenCalledWith(expect.any(Date), { format: 'YYYY-MM-DD', timeZone: '' });
});
});
Loading

0 comments on commit 5e1c007

Please sign in to comment.