@axinom/mosaic-ui 0.34.0-rc.7 → 0.34.0-rc.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.34.0-rc.7",
3
+ "version": "0.34.0-rc.9",
4
4
  "description": "UI components for building Axinom Mosaic applications",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -32,7 +32,7 @@
32
32
  "build-storybook": "storybook build"
33
33
  },
34
34
  "dependencies": {
35
- "@axinom/mosaic-core": "^0.4.7-rc.7",
35
+ "@axinom/mosaic-core": "^0.4.7-rc.9",
36
36
  "@faker-js/faker": "^7.4.0",
37
37
  "@popperjs/core": "^2.9.2",
38
38
  "clsx": "^1.1.0",
@@ -102,5 +102,5 @@
102
102
  "publishConfig": {
103
103
  "access": "public"
104
104
  },
105
- "gitHead": "2a04de5c6ada810610104313331a4b2324cf065f"
105
+ "gitHead": "94ff309a76a395dfa2c13eed746c6603c15df0bd"
106
106
  }
@@ -1,7 +1,12 @@
1
1
  import { mount, shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import { Button } from '../../Buttons';
4
- import { CustomFilterProps, FilterType, FilterTypes } from '../Filters.model';
4
+ import {
5
+ CustomFilterProps,
6
+ FilterType,
7
+ FilterTypes,
8
+ SelectedValueRenderer,
9
+ } from '../Filters.model';
5
10
  import { FreeTextFilter } from '../SelectionTypes/FreeTextFilter/FreeTextFilter';
6
11
  import { OptionsFilter } from '../SelectionTypes/OptionsFilter/OptionsFilter';
7
12
  import { Filter, FilterProps } from './Filter';
@@ -148,6 +153,24 @@ describe('Filter', () => {
148
153
  expect(wrapper.find('.selectedValue').exists()).toBe(false);
149
154
  });
150
155
 
156
+ it(`'selectedValueRenderer' value is displayed when the prop is set`, () => {
157
+ const renderedValue = `${sampleText} renderer`;
158
+ const selectedValueRenderer: SelectedValueRenderer = (value) => {
159
+ return `${value} renderer`;
160
+ };
161
+
162
+ const wrapper = mount(
163
+ <Filter {...defaultProps} options={freeTextFilter} value={sampleText} />,
164
+ );
165
+
166
+ expect(wrapper.find('.selectedValue').text()).toEqual(sampleText);
167
+
168
+ wrapper.setProps({ selectedValueRenderer });
169
+ wrapper.update();
170
+
171
+ expect(wrapper.find('.selectedValue').text()).toEqual(renderedValue);
172
+ });
173
+
151
174
  it('Raises onFilterChange with prop name and new undefined value when filter is closed', () => {
152
175
  const mockValue = 'test-value';
153
176
  const wrapper = mount(
@@ -26,6 +26,7 @@ export interface FilterProps<T extends Data> {
26
26
  index?: number;
27
27
  isActive: boolean;
28
28
  className?: string;
29
+ selectedValueRenderer?: (value: FilterValue) => string;
29
30
  onFilterChange: (prop: keyof T, value: FilterValue, index: number) => void;
30
31
  onValidate?: (currentValue: FilterValue) => string | null | undefined;
31
32
  onFilterClicked: () => void;
@@ -37,6 +38,7 @@ export const Filter = <T extends Data>({
37
38
  index = -1,
38
39
  isActive,
39
40
  className = '',
41
+ selectedValueRenderer,
40
42
  onFilterChange,
41
43
  onFilterClicked,
42
44
  onValidate,
@@ -72,6 +74,10 @@ export const Filter = <T extends Data>({
72
74
  };
73
75
 
74
76
  const renderValue = (value: unknown): ReactNode => {
77
+ if (selectedValueRenderer !== undefined) {
78
+ return selectedValueRenderer(value);
79
+ }
80
+
75
81
  switch (options.type) {
76
82
  case FilterTypes.Date:
77
83
  return formatDate(String(value));
@@ -15,6 +15,7 @@ export interface FilterConfig<T extends Data> {
15
15
  label: string;
16
16
  property: keyof T;
17
17
  type: FilterTypes;
18
+ selectedValueRenderer?: SelectedValueRenderer;
18
19
  onValidate?: FilterValidatorFunction<T>;
19
20
  }
20
21
 
@@ -105,3 +106,5 @@ export type FilterValidatorFunction<T> = (
105
106
  value: FilterValue,
106
107
  allValues: FilterValues<T>,
107
108
  ) => FilterValidationResult;
109
+
110
+ export type SelectedValueRenderer = (value: FilterValue) => string;
@@ -153,6 +153,15 @@ const customFilter: FilterType<{ custom: string }> = {
153
153
  label: 'Custom Filter (multi select)',
154
154
  property: 'custom',
155
155
  type: FilterTypes.Custom,
156
+ selectedValueRenderer: (value: unknown) => {
157
+ const items = value as string[];
158
+
159
+ return String(
160
+ `${items.length} item${items.length === 1 ? '' : 's'}: ${items
161
+ .join(', ')
162
+ .replace(/([a-zA-Z])(\d)/g, '$1 $2')}`,
163
+ );
164
+ },
156
165
  component: CustomFilterComponent,
157
166
  };
158
167
 
@@ -134,6 +134,7 @@ export const Filters = <T extends Data>({
134
134
  index={index}
135
135
  isActive={index === activeFilterIndex}
136
136
  onFilterChange={filtersChangedHandler}
137
+ selectedValueRenderer={filter.selectedValueRenderer}
137
138
  onValidate={(currentValue) =>
138
139
  filter.onValidate &&
139
140
  filter.onValidate(currentValue, activeFilters.current)
@@ -203,6 +203,41 @@ describe('FileUploadControl', () => {
203
203
  );
204
204
  });
205
205
 
206
+ it('allows files with the same name to be uploaded multiple times', () => {
207
+ const spy = jest.fn();
208
+
209
+ const wrapper = mount(
210
+ <FileUploadControl name={'test-name'} onFileSelected={spy} />,
211
+ );
212
+
213
+ const fileInput = wrapper.find('input[type="file"]');
214
+
215
+ // Simulate first file upload
216
+ fileInput.simulate('change', { target: { files: mockFileList } });
217
+
218
+ expect(spy).toHaveBeenCalledTimes(1);
219
+ expect(spy).toHaveBeenCalledWith({
220
+ file: mockFile,
221
+ uploadCompleted: expect.any(Function),
222
+ uploadProgress: expect.any(Function),
223
+ uploadStarted: expect.any(Function),
224
+ });
225
+
226
+ // Reset spy
227
+ spy.mockReset();
228
+
229
+ // Simulate second file upload with the same file
230
+ fileInput.simulate('change', { target: { files: mockFileList } });
231
+
232
+ expect(spy).toHaveBeenCalledTimes(1);
233
+ expect(spy).toHaveBeenCalledWith({
234
+ file: mockFile,
235
+ uploadCompleted: expect.any(Function),
236
+ uploadProgress: expect.any(Function),
237
+ uploadStarted: expect.any(Function),
238
+ });
239
+ });
240
+
206
241
  describe('MIME Types', () => {
207
242
  const mockTypes = 'image/jpeg,image/png';
208
243
  const mockFile = new File([new ArrayBuffer(1)], 'image.png', {
@@ -169,6 +169,8 @@ export const FileUploadControl: React.FC<FileUploadProps> = ({
169
169
  onChange={(event) => {
170
170
  const file = event.target.files?.item(0);
171
171
  file && fileSelected(file);
172
+ // Reset the value of the input field to ensure onChange fires even with same file
173
+ event.target.value = '';
172
174
  }}
173
175
  />
174
176
  </>