diff --git a/.changeset/immutable-v5-cmf-cqrs-major.md b/.changeset/immutable-v5-cmf-cqrs-major.md
new file mode 100644
index 00000000000..5ded9be2e48
--- /dev/null
+++ b/.changeset/immutable-v5-cmf-cqrs-major.md
@@ -0,0 +1,13 @@
+---
+'@talend/react-cmf-cqrs': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`).
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.changeset/immutable-v5-cmf-major.md b/.changeset/immutable-v5-cmf-major.md
new file mode 100644
index 00000000000..b1523218f2e
--- /dev/null
+++ b/.changeset/immutable-v5-cmf-major.md
@@ -0,0 +1,15 @@
+---
+'@talend/react-cmf': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`). All cmf source and expressions modules have been updated accordingly.
+- **`Iterable` removed**: Replace `Immutable.Iterable` checks with `isImmutable()` from `immutable`.
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+- **`OrderedMap` → `Map`**: `Map` in Immutable v5 preserves insertion order, making `OrderedMap` redundant. All internal usage has been updated.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.changeset/immutable-v5-components-major.md b/.changeset/immutable-v5-components-major.md
new file mode 100644
index 00000000000..a2ba3eaae68
--- /dev/null
+++ b/.changeset/immutable-v5-components-major.md
@@ -0,0 +1,14 @@
+---
+'@talend/react-components': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`). ActionDropdown and other components have been updated accordingly.
+- **`Iterable` removed**: Replace `Immutable.Iterable` checks with `isImmutable()` from `immutable`.
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.changeset/immutable-v5-containers-major.md b/.changeset/immutable-v5-containers-major.md
new file mode 100644
index 00000000000..cb09b9468ca
--- /dev/null
+++ b/.changeset/immutable-v5-containers-major.md
@@ -0,0 +1,15 @@
+---
+'@talend/react-containers': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`).
+- **`Iterable` removed**: Replace `Immutable.Iterable` checks with `isImmutable()` from `immutable`.
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+- **`OrderedMap` → `Map`**: `Map` in Immutable v5 preserves insertion order, making `OrderedMap` redundant. All internal usage has been updated.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.changeset/immutable-v5-flow-designer-major.md b/.changeset/immutable-v5-flow-designer-major.md
new file mode 100644
index 00000000000..dbe868d18f3
--- /dev/null
+++ b/.changeset/immutable-v5-flow-designer-major.md
@@ -0,0 +1,15 @@
+---
+'@talend/react-flow-designer': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`). Reducers (link, node, port) and renderers (LinksRenderer, NodesRenderer, PortsRenderer) have been updated accordingly.
+- **`Iterable` removed**: Replace `Immutable.Iterable` checks with `isImmutable()` from `immutable`.
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+- **`OrderedMap` → `Map`**: `Map` in Immutable v5 preserves insertion order, making `OrderedMap` redundant. All internal usage has been updated.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.changeset/immutable-v5-sagas-major.md b/.changeset/immutable-v5-sagas-major.md
new file mode 100644
index 00000000000..ab16708143c
--- /dev/null
+++ b/.changeset/immutable-v5-sagas-major.md
@@ -0,0 +1,13 @@
+---
+'@talend/react-sagas': major
+---
+
+Upgrade Immutable.js to v5
+
+## Breaking Changes
+
+- **Immutable.js upgraded from v3.8.2 to v5.x**: Consumers depending on Immutable v3 or v4 APIs must update accordingly.
+- **Default import removed**: `import Immutable from 'immutable'` is no longer supported. Use named imports instead (e.g., `import { Map, List, fromJS, isImmutable } from 'immutable'`).
+- **`react-immutable-proptypes` removed**: Custom internal validators replace `ImmutablePropTypes`. No peer-dep on `react-immutable-proptypes` anymore.
+
+See the [migration guide](../docs/breaking-change-immutable-v5.md) for full details and upgrade instructions.
diff --git a/.gitignore b/.gitignore
index ed9f9e57949..4fc76121a4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,3 +51,10 @@ eslint-report.json
stylelint-report.json
i18n-extract
.test-cache
+
+# TMP
+_bmad
+_bmad-*
+.github/agents/bmad-*
+.github/prompts/bmad_*
+.github/prompts/bmad-*
diff --git a/.prettierignore b/.prettierignore
index 34f6040084a..482dc82ad41 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -8,3 +8,10 @@ dist
node_modules
__fixtures__
tools/scripts-config-storybook-lib/.storybook-templates/main.js
+
+# TMP
+_bmad
+_bmad-output
+.github/agents/bmad-*
+.github/prompts/bmad_*
+.github/prompts/bmad-*
diff --git a/docs/breaking-change-immutable-v5.md b/docs/breaking-change-immutable-v5.md
new file mode 100644
index 00000000000..c850c1d2723
--- /dev/null
+++ b/docs/breaking-change-immutable-v5.md
@@ -0,0 +1,160 @@
+# Breaking Changes: Immutable.js v5 Migration
+
+This document covers the breaking changes introduced by the Immutable.js v5 migration
+across the following packages:
+
+- `@talend/react-cmf`
+- `@talend/react-components`
+- `@talend/react-containers`
+- `@talend/react-flow-designer`
+- `@talend/react-cmf-cqrs`
+- `@talend/react-sagas`
+
+---
+
+## 1. Immutable.js upgraded from v3.8.2 to v5.x
+
+The `immutable` peer dependency has been bumped to `^5.0.0`.
+
+Immutable v5 ships significant performance improvements and API clean-ups relative to v3/v4.
+Consumers must upgrade their own `immutable` dependency and review any private API usage.
+
+**Action required:** Update your `package.json`:
+
+```json
+{
+ "dependencies": {
+ "immutable": "^5.0.0"
+ }
+}
+```
+
+---
+
+## 2. Default import removed
+
+The default export of `immutable` no longer exists in v5. Any code relying on the default
+import will fail at runtime.
+
+**Before:**
+
+```js
+import Immutable from 'immutable';
+
+const map = Immutable.Map({ key: 'value' });
+const list = Immutable.List([1, 2, 3]);
+```
+
+**After:**
+
+```js
+import { Map, List, fromJS, isImmutable } from 'immutable';
+
+const map = Map({ key: 'value' });
+const list = List([1, 2, 3]);
+```
+
+---
+
+## 3. `Iterable` replaced by `isImmutable()`
+
+`Immutable.Iterable` (and the `Iterable.isIterable()` helper) were removed in v5.
+Use the top-level `isImmutable()` function to check whether a value is an Immutable
+data structure.
+
+**Before:**
+
+```js
+import Immutable from 'immutable';
+
+if (Immutable.Iterable.isIterable(value)) {
+ // ...
+}
+```
+
+**After:**
+
+```js
+import { isImmutable } from 'immutable';
+
+if (isImmutable(value)) {
+ // ...
+}
+```
+
+---
+
+## 4. `react-immutable-proptypes` removed
+
+The `react-immutable-proptypes` package has been removed from all affected packages.
+Custom lightweight validators (provided internally) replace it.
+
+If your application depends on `ImmutablePropTypes` from `react-immutable-proptypes`,
+you must either:
+
+- Remove the dependency and write plain PropTypes validators, **or**
+- Keep `react-immutable-proptypes` as a direct dependency of your own package.
+
+**Before (in your component):**
+
+```js
+import ImmutablePropTypes from 'react-immutable-proptypes';
+
+MyComponent.propTypes = {
+ items: ImmutablePropTypes.list.isRequired,
+};
+```
+
+**After (example using plain PropTypes + isImmutable):**
+
+```js
+import PropTypes from 'prop-types';
+import { isImmutable } from 'immutable';
+
+MyComponent.propTypes = {
+ items: (props, propName) => {
+ if (!isImmutable(props[propName])) {
+ return new Error(`${propName} must be an Immutable structure`);
+ }
+ return null;
+ },
+};
+```
+
+---
+
+## 5. `OrderedMap` replaced by `Map`
+
+Immutable v5's `Map` preserves insertion order by default, making `OrderedMap`
+redundant. All internal usages of `OrderedMap` have been replaced with `Map`.
+
+If your code uses `OrderedMap` directly from these packages' re-exports or expects
+`OrderedMap` instances from props/state, switch to `Map`.
+
+**Before:**
+
+```js
+import Immutable from 'immutable';
+
+const ordered = Immutable.OrderedMap({ a: 1, b: 2 });
+```
+
+**After:**
+
+```js
+import { Map } from 'immutable';
+
+const map = Map({ a: 1, b: 2 }); // insertion order preserved in v5
+```
+
+---
+
+## Migration Summary
+
+| Change | v3 / v4 | v5 |
+| ---------------- | ----------------------------------- | ------------------------------------------ |
+| Package import | `import Immutable from 'immutable'` | `import { Map, List, … } from 'immutable'` |
+| Iterable check | `Immutable.Iterable.isIterable(x)` | `isImmutable(x)` |
+| Ordered map | `OrderedMap({ … })` | `Map({ … })` |
+| PropTypes | `react-immutable-proptypes` | Custom validators / plain PropTypes |
+| Peer dep version | `^3.8.2` or `^4.0.0` | `^5.0.0` |
diff --git a/packages/cmf-cqrs/package.json b/packages/cmf-cqrs/package.json
index 28c5ea1ce18..d316f559706 100644
--- a/packages/cmf-cqrs/package.json
+++ b/packages/cmf-cqrs/package.json
@@ -43,7 +43,7 @@
"dependencies": {
"@talend/react-cmf": "^12.1.0",
"@talend/utils": "^3.7.0",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"redux-saga": "^1.4.2"
},
"devDependencies": {
diff --git a/packages/cmf/__tests__/componentState.test.js b/packages/cmf/__tests__/componentState.test.js
index 04609ddee19..4f438e6d133 100644
--- a/packages/cmf/__tests__/componentState.test.js
+++ b/packages/cmf/__tests__/componentState.test.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import Immutable, { Map } from 'immutable';
+import { Map, fromJS } from 'immutable';
import state, {
getStateAccessors,
@@ -67,7 +67,7 @@ describe('state', () => {
it('should getStateProps return state', () => {
const storeState = {
cmf: {
- components: Immutable.fromJS({
+ components: fromJS({
foo: {
bar: {
open: true,
diff --git a/packages/cmf/__tests__/expressions/index.test.js b/packages/cmf/__tests__/expressions/index.test.js
index f13a854920d..0800593cb6a 100644
--- a/packages/cmf/__tests__/expressions/index.test.js
+++ b/packages/cmf/__tests__/expressions/index.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { Map, List } from 'immutable';
import expressions from '../../src/expressions';
import { mock } from '../../src';
@@ -13,8 +13,8 @@ describe('expressions', () => {
it('should get collection content', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'my title',
}),
});
@@ -27,7 +27,7 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({});
+ state.cmf.collections = new Map({});
expect(expressions['cmf.collections.get']({ context }, 'article.title', 'no title')).toBe(
'no title',
);
@@ -38,10 +38,10 @@ describe('expressions', () => {
it('should return true if the value is present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -52,10 +52,10 @@ describe('expressions', () => {
it('should return false if the value is not present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -67,7 +67,7 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({});
+ state.cmf.collections = new Map({});
expect(expressions['cmf.collections.includes']({ context }, 'article.tags', 'test')).toBe(
false,
);
@@ -77,10 +77,10 @@ describe('expressions', () => {
it('should return true if one of the values is present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -91,10 +91,10 @@ describe('expressions', () => {
it('should return false if all values are not present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -106,7 +106,7 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({});
+ state.cmf.collections = new Map({});
expect(
expressions['cmf.collections.oneOf']({ context }, 'article.tags', ['test0', 'test1']),
).toBe(false);
@@ -115,10 +115,10 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
expect(() =>
@@ -130,10 +130,10 @@ describe('expressions', () => {
it('should return true if all of the values are present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -148,10 +148,10 @@ describe('expressions', () => {
it('should return false if not all values are not present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
context.store.getState = () => state;
@@ -163,7 +163,7 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({});
+ state.cmf.collections = new Map({});
expect(
expressions['cmf.collections.allOf']({ context }, 'article.tags', ['test0', 'test1']),
).toBe(false);
@@ -172,10 +172,10 @@ describe('expressions', () => {
const context = mock.store.context();
const state = mock.store.state();
context.store.getState = () => state;
- state.cmf.collections = new Immutable.Map({
- article: new Immutable.Map({
+ state.cmf.collections = new Map({
+ article: new Map({
title: 'title',
- tags: new Immutable.List(['test', 'test2', 'test3']),
+ tags: new List(['test', 'test2', 'test3']),
}),
});
expect(() =>
@@ -188,9 +188,9 @@ describe('expressions', () => {
it('should get component state', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.components = new Immutable.Map({
- MyComponent: new Immutable.Map({
- default: new Immutable.Map({
+ state.cmf.components = new Map({
+ MyComponent: new Map({
+ default: new Map({
show: true,
}),
}),
@@ -203,7 +203,7 @@ describe('expressions', () => {
it('should return default value if no component state', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.components = new Immutable.Map({});
+ state.cmf.components = new Map({});
context.store.getState = () => state;
expect(
expressions['cmf.components.get']({ context }, 'MyComponent.default.show', false),
@@ -215,10 +215,10 @@ describe('expressions', () => {
it('should return true if the value is present in the list', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.components = new Immutable.Map({
- MyComponent: new Immutable.Map({
- default: new Immutable.Map({
- tags: new Immutable.List(['tag1', 'tag2', 'tag3']),
+ state.cmf.components = new Map({
+ MyComponent: new Map({
+ default: new Map({
+ tags: new List(['tag1', 'tag2', 'tag3']),
show: true,
}),
}),
@@ -231,7 +231,7 @@ describe('expressions', () => {
it('should return default false if there is no component state', () => {
const context = mock.store.context();
const state = mock.store.state();
- state.cmf.components = new Immutable.Map({});
+ state.cmf.components = new Map({});
context.store.getState = () => state;
expect(
expressions['cmf.components.includes']({ context }, 'MyComponent.default.tags', 'tag1'),
diff --git a/packages/cmf/__tests__/localStorage.test.js b/packages/cmf/__tests__/localStorage.test.js
index 6c31efa4beb..21c8568e8b4 100644
--- a/packages/cmf/__tests__/localStorage.test.js
+++ b/packages/cmf/__tests__/localStorage.test.js
@@ -1,4 +1,7 @@
-import Immutable from 'immutable';
+/**
+ * @jest-environment jest-environment-jsdom-global
+ */
+import { Map, List } from 'immutable';
import localStorageAPI from '../src/localStorage';
const PATHS = [
@@ -12,33 +15,35 @@ const state = {
app: {
extra: true,
},
- components: new Immutable.Map({
- Foo: new Immutable.Map({
- default: new Immutable.Map({
+ components: new Map({
+ Foo: new Map({
+ default: new Map({
foo: 'foo',
}),
}),
}),
- collections: new Immutable.Map({
- data: new Immutable.Map({}),
+ collections: new Map({
+ data: new Map({}),
}),
},
};
-const serializedState = JSON.stringify(Object.assign({}, state, {
- cmf: {
- components: {
- Foo: {
- default: {
- foo: 'foo',
+const serializedState = JSON.stringify(
+ Object.assign({}, state, {
+ cmf: {
+ components: {
+ Foo: {
+ default: {
+ foo: 'foo',
+ },
},
},
+ collections: {
+ data: {},
+ },
},
- collections: {
- data: {},
- },
- },
-}));
+ }),
+);
const KEY = 'test-cmf-localStorage';
describe('reduxLocalStorage', () => {
@@ -60,6 +65,26 @@ describe('reduxLocalStorage', () => {
expect(initialState.cmf.collections.getIn(['data']).toJS()).toEqual({});
localStorage.setItem(KEY, undefined);
});
+ it('should getState restore arrays as immutable Lists', () => {
+ const stateWithList = JSON.stringify({
+ cmf: {
+ components: {
+ Foo: {
+ default: {
+ items: ['a', 'b', 'c'],
+ },
+ },
+ },
+ collections: {},
+ },
+ });
+ localStorage.setItem(KEY, stateWithList);
+ const initialState = localStorageAPI.getState(KEY);
+ const items = initialState.cmf.components.getIn(['Foo', 'default', 'items']);
+ expect(List.isList(items)).toBe(true);
+ expect(items.toJS()).toEqual(['a', 'b', 'c']);
+ localStorage.setItem(KEY, undefined);
+ });
it('should getStoreCallback return a function', () => {
const callback = localStorageAPI.getStoreCallback(KEY, PATHS);
expect(typeof callback).toBe('function');
diff --git a/packages/cmf/__tests__/onEvent.test.js b/packages/cmf/__tests__/onEvent.test.js
index 4d7a0d3d769..bf3125617a7 100644
--- a/packages/cmf/__tests__/onEvent.test.js
+++ b/packages/cmf/__tests__/onEvent.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import onEvent from '../src/onEvent';
describe('onEvent', () => {
@@ -10,7 +10,7 @@ describe('onEvent', () => {
instance = {
props: {
setState: jest.fn(),
- state: new Immutable.Map({ docked: false }),
+ state: new Map({ docked: false }),
},
};
config = {};
diff --git a/packages/cmf/__tests__/sagas/collection.test.js b/packages/cmf/__tests__/sagas/collection.test.js
index 3cc85213091..6c3168cfe0f 100644
--- a/packages/cmf/__tests__/sagas/collection.test.js
+++ b/packages/cmf/__tests__/sagas/collection.test.js
@@ -1,18 +1,16 @@
import { delay, call, select } from 'redux-saga/effects';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import selectors from '../../src/selectors';
-import {
- waitFor,
-} from '../../src/sagas/collection';
+import { waitFor } from '../../src/sagas/collection';
describe('waitFor', () => {
it('should waitFor wait for a collection to exists', () => {
const withoutCollection = {
cmf: {
- collections: new Immutable.Map({}),
+ collections: new Map({}),
},
};
- const withCollection = withoutCollection.cmf.collections.set('foo', new Immutable.Map({}));
+ const withCollection = withoutCollection.cmf.collections.set('foo', new Map({}));
const gen = waitFor('foo');
expect(gen.next().value).toEqual(select(selectors.collections.get, 'foo'));
expect(gen.next().value).toEqual(delay(10));
diff --git a/packages/cmf/__tests__/selectors/toJS.test.js b/packages/cmf/__tests__/selectors/toJS.test.js
index 553be88fcef..8a30fb40def 100644
--- a/packages/cmf/__tests__/selectors/toJS.test.js
+++ b/packages/cmf/__tests__/selectors/toJS.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import toJS from '../../src/selectors/toJS';
describe('toJS', () => {
@@ -12,7 +12,7 @@ describe('toJS', () => {
it('the returned function should call toJS on the results', () => {
const myselector = toJS(selector);
const state = {
- foo: new Immutable.Map({ bar: 'bar' }),
+ foo: new Map({ bar: 'bar' }),
};
const result = myselector(state);
expect(result).toEqual({ bar: 'bar' });
@@ -20,7 +20,7 @@ describe('toJS', () => {
it('the returned function should return same reference on multiple calls', () => {
const myselector = toJS(selector);
const state = {
- foo: new Immutable.Map({ bar: 'bar' }),
+ foo: new Map({ bar: 'bar' }),
};
const result1 = myselector(state);
const result2 = myselector(state);
@@ -29,7 +29,7 @@ describe('toJS', () => {
it('the returned function should return a different result if store is has been modified', () => {
const myselector = toJS(selector);
const state = {
- foo: new Immutable.Map({ bar: 'bar' }),
+ foo: new Map({ bar: 'bar' }),
};
const result1 = myselector(state);
state.foo = state.foo.set('bar', 'baz');
diff --git a/packages/cmf/package.json b/packages/cmf/package.json
index 17a8672512b..68648502517 100644
--- a/packages/cmf/package.json
+++ b/packages/cmf/package.json
@@ -46,13 +46,12 @@
"@talend/utils": "^3.7.0",
"commander": "^6.2.1",
"hoist-non-react-statics": "^3.3.2",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"invariant": "^2.2.4",
"lodash": "^4.17.23",
"nested-combine-reducers": "^1.2.2",
"path-to-regexp": "^8.3.0",
"prop-types": "^15.8.1",
- "react-immutable-proptypes": "^2.2.0",
"react-redux": "^7.2.9",
"redux": "^4.2.1",
"redux-batched-actions": "^0.5.0",
diff --git a/packages/cmf/src/cmfConnect.jsx b/packages/cmf/src/cmfConnect.jsx
index 3950c99b989..ad707f2534f 100644
--- a/packages/cmf/src/cmfConnect.jsx
+++ b/packages/cmf/src/cmfConnect.jsx
@@ -24,8 +24,8 @@ export default cmfConnect({
import PropTypes from 'prop-types';
import { useState, useContext, useEffect, forwardRef } from 'react';
import hoistStatics from 'hoist-non-react-statics';
-import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect, useStore } from 'react-redux';
+import { immutableMapPropType } from './propTypes/immutable';
import { randomUUID } from '@talend/utils';
import actions from './actions';
import actionCreator from './actionCreator';
@@ -392,8 +392,8 @@ cmfConnect.omit = omit;
cmfConnect.omitAllProps = props => cmfConnect.omit(props, cmfConnect.ALL_INJECTED_PROPS);
cmfConnect.propTypes = {
- state: ImmutablePropTypes.map,
- initialState: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.object]),
+ state: immutableMapPropType,
+ initialState: PropTypes.oneOfType([immutableMapPropType, PropTypes.object]),
getComponent: PropTypes.func,
setState: PropTypes.func,
initState: PropTypes.func,
diff --git a/packages/cmf/src/cmfConnect.md b/packages/cmf/src/cmfConnect.md
index df36fd10eb6..4859b3572dd 100644
--- a/packages/cmf/src/cmfConnect.md
+++ b/packages/cmf/src/cmfConnect.md
@@ -35,7 +35,7 @@ This is required.
```javascript
// example adapted from https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
-const DEFAULT_STATE = new Immutable.Map({ date: new Date() });
+const DEFAULT_STATE = new Map({ date: new Date() });
class Clock extends React.Component {
static displayName = 'Clock'; // required
@@ -78,7 +78,7 @@ export default cmfConnect({
// This will create the state in redux at state.cmf.components.getIn(['Clock', 'default'])
```
-First you should use immutable data structure, the `setState` of CMF uses `Immutable.fromJS` to convert its content.
+First you should use immutable data structure, the `setState` of CMF uses `fromJS` to convert its content.
The main idea behind is to remove the need to write reducer.
diff --git a/packages/cmf/src/componentState.js b/packages/cmf/src/componentState.js
index d63c1417f81..229690ea334 100644
--- a/packages/cmf/src/componentState.js
+++ b/packages/cmf/src/componentState.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import Immutable from 'immutable';
+import { Map, fromJS } from 'immutable';
import actions from './actions';
/**
@@ -69,7 +69,7 @@ export function getStateAccessors(dispatch, name, id, DEFAULT_STATE) {
if (DEFAULT_STATE) {
state = DEFAULT_STATE.merge(initialState);
} else if (initialState) {
- state = Immutable.Map.isMap(initialState) ? initialState : Immutable.fromJS(initialState);
+ state = Map.isMap(initialState) ? initialState : fromJS(initialState);
}
if (state) {
const componentState = actions.components.addState(name, id, state);
diff --git a/packages/cmf/src/expressions/allOf.js b/packages/cmf/src/expressions/allOf.js
index 38e1b28c964..d6634fdd937 100644
--- a/packages/cmf/src/expressions/allOf.js
+++ b/packages/cmf/src/expressions/allOf.js
@@ -1,14 +1,14 @@
import get from 'lodash/get';
-import Immutable from 'immutable';
+import { Map, List } from 'immutable';
export default function getAllOfFunction(statePath) {
return function includes({ context }, immutablePath, values) {
if (!Array.isArray(values)) {
throw new Error('You should pass an array of values to check if all of them are present');
}
- const arr = get(context.store.getState(), statePath, new Immutable.Map()).getIn(
+ const arr = get(context.store.getState(), statePath, new Map()).getIn(
immutablePath.split('.'),
- new Immutable.List(),
+ new List(),
);
return arr.size > 0 && arr.every(value => values.includes(value));
};
diff --git a/packages/cmf/src/expressions/getInState.js b/packages/cmf/src/expressions/getInState.js
index 67eadc66f23..a876a18804f 100644
--- a/packages/cmf/src/expressions/getInState.js
+++ b/packages/cmf/src/expressions/getInState.js
@@ -1,9 +1,9 @@
import _get from 'lodash/get';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import curry from 'lodash/curry';
function getInState(statePath, { context }, immutablePath, defaultValue) {
- return _get(context.store.getState(), statePath, new Immutable.Map()).getIn(
+ return _get(context.store.getState(), statePath, new Map()).getIn(
immutablePath.split('.'),
defaultValue,
);
diff --git a/packages/cmf/src/expressions/includes.js b/packages/cmf/src/expressions/includes.js
index ed94cadb2a5..e41a2a3a1c8 100644
--- a/packages/cmf/src/expressions/includes.js
+++ b/packages/cmf/src/expressions/includes.js
@@ -1,10 +1,10 @@
import _get from 'lodash/get';
-import Immutable from 'immutable';
+import { Map, List } from 'immutable';
export default function getIncludesFunction(statePath) {
return function includes({ context }, immutablePath, value) {
- return _get(context.store.getState(), statePath, new Immutable.Map())
- .getIn(immutablePath.split('.'), new Immutable.List())
+ return _get(context.store.getState(), statePath, new Map())
+ .getIn(immutablePath.split('.'), new List())
.includes(value);
};
}
diff --git a/packages/cmf/src/expressions/index.md b/packages/cmf/src/expressions/index.md
index be4a5737b2f..01ab2c3275b 100644
--- a/packages/cmf/src/expressions/index.md
+++ b/packages/cmf/src/expressions/index.md
@@ -16,10 +16,10 @@ For all the following example we take this component as example:
```javascript
import React from 'react';
import PropTypes from 'prop-types';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import { cmfConnect } from '@talend/react-cmf';
-const DEFAULT_STATE = new Immutable.Map({
+const DEFAULT_STATE = new Map({
like: false,
});
@@ -101,6 +101,7 @@ export cmfConnect({mapStateToProps})(MyComponent)
}
}
```
+
### allOf
```json
diff --git a/packages/cmf/src/expressions/oneOf.js b/packages/cmf/src/expressions/oneOf.js
index a040c6bc92d..943f1e0db35 100644
--- a/packages/cmf/src/expressions/oneOf.js
+++ b/packages/cmf/src/expressions/oneOf.js
@@ -1,14 +1,14 @@
import get from 'lodash/get';
-import Immutable from 'immutable';
+import { Map, List } from 'immutable';
export default function getOneOfFunction(statePath) {
return function includes({ context }, immutablePath, values) {
if (!Array.isArray(values)) {
throw new Error('You should pass an array of values to check if one of them is present');
}
- const arr = get(context.store.getState(), statePath, new Immutable.Map()).getIn(
+ const arr = get(context.store.getState(), statePath, new Map()).getIn(
immutablePath.split('.'),
- new Immutable.List(),
+ new List(),
);
return values.some(value => arr.includes(value));
};
diff --git a/packages/cmf/src/index.js b/packages/cmf/src/index.js
index 147cd642ffa..b4278a8fd82 100644
--- a/packages/cmf/src/index.js
+++ b/packages/cmf/src/index.js
@@ -19,6 +19,7 @@ import ConnectedDispatcher from './Dispatcher';
import expression from './expression';
import expressions from './expressions';
import Inject from './Inject.component';
+import { immutableListPropType, immutableMapPropType } from './propTypes/immutable';
import localStorage from './localStorage';
import matchPath from './matchPath';
import middlewares from './middlewares';
@@ -63,6 +64,8 @@ export {
CmfRegisteredSaga,
store,
useCMFContext,
+ immutableMapPropType,
+ immutableListPropType,
};
/**
diff --git a/packages/cmf/src/localStorage.js b/packages/cmf/src/localStorage.js
index 595be0a4adc..c656e4597f9 100644
--- a/packages/cmf/src/localStorage.js
+++ b/packages/cmf/src/localStorage.js
@@ -1,8 +1,8 @@
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import set from 'lodash/set';
/**
- * getState read localStorage and create a initilState for redux
+ * getState read localStorage and create a initialState for redux
* @param {string} key the localStorage key where to read
* @return {Object} initialState for redux
*/
@@ -14,10 +14,10 @@ function getState(key) {
source = JSON.parse(source);
if (source.cmf) {
if (source.cmf.components) {
- source.cmf.components = Immutable.fromJS(source.cmf.components);
+ source.cmf.components = fromJS(source.cmf.components);
}
if (source.cmf.collections) {
- source.cmf.collections = Immutable.fromJS(source.cmf.collections);
+ source.cmf.collections = fromJS(source.cmf.collections);
}
}
return source;
diff --git a/packages/cmf/src/onEvent.js b/packages/cmf/src/onEvent.js
index 9540e1c6c6b..41f495d7d4d 100644
--- a/packages/cmf/src/onEvent.js
+++ b/packages/cmf/src/onEvent.js
@@ -1,5 +1,5 @@
import get from 'lodash/get';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import CONSTANT from './constant';
function serializeEvent(event) {
@@ -84,7 +84,7 @@ const ACTION_CREATOR = 'ACTION_CREATOR';
const DISPATCH = 'DISPATCH';
const SETSTATE = 'SETSTATE';
-const INITIAL_STATE = new Immutable.Map();
+const INITIAL_STATE = new Map();
function addOnEventSupport(handlerType, instance, props, key) {
if (CONSTANT[`IS_HANDLER_${handlerType}_REGEX`].test(key)) {
diff --git a/packages/cmf/src/propTypes/immutable.js b/packages/cmf/src/propTypes/immutable.js
new file mode 100644
index 00000000000..d84d760f9b5
--- /dev/null
+++ b/packages/cmf/src/propTypes/immutable.js
@@ -0,0 +1,37 @@
+// TODO: consider moving these validators to @talend/utils to avoid duplication
+// with packages/components/src/propTypes/immutable.js.
+import { Map, List } from 'immutable';
+
+function immutableMapPropType(props, propName, componentName) {
+ if (props[propName] != null && !Map.isMap(props[propName])) {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected an Immutable.Map.`,
+ );
+ }
+ return null;
+}
+
+function immutableListPropType(props, propName, componentName) {
+ if (props[propName] != null && !List.isList(props[propName])) {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected an Immutable.List.`,
+ );
+ }
+ return null;
+}
+
+function makeRequired(validator) {
+ return function isRequired(props, propName, componentName) {
+ if (props[propName] == null) {
+ return new Error(
+ `The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is \`${props[propName]}\`.`,
+ );
+ }
+ return validator(props, propName, componentName);
+ };
+}
+
+immutableMapPropType.isRequired = makeRequired(immutableMapPropType);
+immutableListPropType.isRequired = makeRequired(immutableListPropType);
+
+export { immutableMapPropType, immutableListPropType };
diff --git a/packages/cmf/src/propTypes/immutable.test.js b/packages/cmf/src/propTypes/immutable.test.js
new file mode 100644
index 00000000000..65db5966d06
--- /dev/null
+++ b/packages/cmf/src/propTypes/immutable.test.js
@@ -0,0 +1,128 @@
+import { Map, List } from 'immutable';
+import { immutableMapPropType, immutableListPropType } from './immutable';
+
+describe('immutableMapPropType', () => {
+ it('should return null when prop is an Immutable.Map', () => {
+ const props = { state: Map() };
+ expect(immutableMapPropType(props, 'state', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is undefined (optional)', () => {
+ const props = {};
+ expect(immutableMapPropType(props, 'state', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is null (optional)', () => {
+ const props = { state: null };
+ expect(immutableMapPropType(props, 'state', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is a plain object', () => {
+ const props = { state: {} };
+ const result = immutableMapPropType(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ expect(result.message).toContain('state');
+ expect(result.message).toContain('TestComponent');
+ expect(result.message).toContain('Immutable.Map');
+ });
+
+ it('should return Error when prop is an array', () => {
+ const props = { state: [] };
+ const result = immutableMapPropType(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is an Immutable.List', () => {
+ const props = { state: List() };
+ const result = immutableMapPropType(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
+
+describe('immutableMapPropType.isRequired', () => {
+ it('should return Error when prop is undefined', () => {
+ const props = {};
+ const result = immutableMapPropType.isRequired(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is null', () => {
+ const props = { state: null };
+ const result = immutableMapPropType.isRequired(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return null when prop is an Immutable.Map', () => {
+ const props = { state: Map() };
+ expect(immutableMapPropType.isRequired(props, 'state', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is not an Immutable.Map', () => {
+ const props = { state: {} };
+ const result = immutableMapPropType.isRequired(props, 'state', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
+
+describe('immutableListPropType', () => {
+ it('should return null when prop is an Immutable.List', () => {
+ const props = { items: List() };
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is undefined (optional)', () => {
+ const props = {};
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is null (optional)', () => {
+ const props = { items: null };
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is a plain array', () => {
+ const props = { items: [] };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ expect(result.message).toContain('items');
+ expect(result.message).toContain('TestComponent');
+ expect(result.message).toContain('Immutable.List');
+ });
+
+ it('should return Error when prop is a plain object', () => {
+ const props = { items: {} };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is an Immutable.Map', () => {
+ const props = { items: Map() };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
+
+describe('immutableListPropType.isRequired', () => {
+ it('should return Error when prop is undefined', () => {
+ const props = {};
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is null', () => {
+ const props = { items: null };
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return null when prop is an Immutable.List', () => {
+ const props = { items: List() };
+ expect(immutableListPropType.isRequired(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is not an Immutable.List', () => {
+ const props = { items: [] };
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
diff --git a/packages/components/package.json b/packages/components/package.json
index 178ad4e6e17..4fef1fa6e04 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -57,7 +57,7 @@
"date-fns": "^3.6.0",
"dom-helpers": "^3.4.0",
"focus-outline-manager": "^1.0.2",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"invariant": "^2.2.4",
"lodash": "^4.17.23",
"memoize-one": "^6.0.0",
@@ -66,7 +66,6 @@
"react-debounce-input": "^3.3.0",
"react-draggable": "^4.5.0",
"react-grid-layout": "^1.5.3",
- "react-immutable-proptypes": "^2.2.0",
"react-is": "^18.3.1",
"react-popper": "^2.3.0",
"react-transition-group": "^2.9.0",
diff --git a/packages/components/src/Actions/ActionDropdown/ActionDropdown.component.jsx b/packages/components/src/Actions/ActionDropdown/ActionDropdown.component.jsx
index 36c0350e3c3..2d1b1840c5b 100644
--- a/packages/components/src/Actions/ActionDropdown/ActionDropdown.component.jsx
+++ b/packages/components/src/Actions/ActionDropdown/ActionDropdown.component.jsx
@@ -1,10 +1,10 @@
import { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import { immutableListPropType } from '../../propTypes/immutable';
import get from 'lodash/get';
import classNames from 'classnames';
-import { Iterable } from 'immutable';
+import { isImmutable } from 'immutable';
import { DropdownButton, MenuItem } from '@talend/react-bootstrap';
import { withTranslation } from 'react-i18next';
import omit from 'lodash/omit';
@@ -96,7 +96,7 @@ function renderMutableMenuItem(item, index, getComponent) {
}
function getMenuItem(item, index, getComponent) {
- if (Iterable.isIterable(item)) {
+ if (isImmutable(item)) {
return renderMutableMenuItem(item.toJS(), index, getComponent);
}
@@ -323,7 +323,7 @@ ActionDropdown.propTypes = {
...MenuItem.propTypes,
}),
),
- ImmutablePropTypes.list,
+ immutableListPropType,
]),
badge: PropTypes.shape({
className: PropTypes.string,
diff --git a/packages/components/src/Actions/ActionDropdown/ActionDropdown.snapshot.test.jsx b/packages/components/src/Actions/ActionDropdown/ActionDropdown.snapshot.test.jsx
index b0e3ba26459..646a3f15d77 100644
--- a/packages/components/src/Actions/ActionDropdown/ActionDropdown.snapshot.test.jsx
+++ b/packages/components/src/Actions/ActionDropdown/ActionDropdown.snapshot.test.jsx
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import { render, screen, within } from '@testing-library/react';
import ActionDropdown from './ActionDropdown.component';
@@ -13,7 +13,7 @@ const items = [
onClick: jest.fn(),
},
];
-const immutableItems = Immutable.fromJS(items);
+const immutableItems = fromJS(items);
describe('ActionDropdown', () => {
it('should render a button dropdown with its menu', () => {
diff --git a/packages/components/src/Actions/ActionDropdown/ActionDropdown.test.jsx b/packages/components/src/Actions/ActionDropdown/ActionDropdown.test.jsx
index 521ba6be240..6615ae19c97 100644
--- a/packages/components/src/Actions/ActionDropdown/ActionDropdown.test.jsx
+++ b/packages/components/src/Actions/ActionDropdown/ActionDropdown.test.jsx
@@ -1,6 +1,7 @@
/* eslint-disable react/prop-types */
/* eslint-disable react/display-name */
+import { fromJS } from 'immutable';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
@@ -124,6 +125,13 @@ describe('getMenuItem', () => {
expect(screen.getByRole('menuitem')).toHaveTextContent('Toto');
expect(screen.getByRole('menuitem')).toHaveAttribute('data-feature', 'action.feature');
});
+ it('should call toJS() and render correctly when item is an Immutable Map', () => {
+ const item = fromJS({ label: 'Immutable Item', 'data-feature': 'immutable.feature' });
+ render(getMenuItem(item, 0, undefined));
+ expect(screen.getByRole('menuitem')).toBeInTheDocument();
+ expect(screen.getByRole('menuitem')).toHaveTextContent('Immutable Item');
+ expect(screen.getByRole('menuitem')).toHaveAttribute('data-feature', 'immutable.feature');
+ });
});
describe('InjectDropdownMenuItem', () => {
diff --git a/packages/components/src/Actions/ActionDropdown/Dropdown.stories.jsx b/packages/components/src/Actions/ActionDropdown/Dropdown.stories.jsx
index e2b9783bcf8..282e328565b 100644
--- a/packages/components/src/Actions/ActionDropdown/Dropdown.stories.jsx
+++ b/packages/components/src/Actions/ActionDropdown/Dropdown.stories.jsx
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import FilterBar from '../../FilterBar';
import Action from '../Action';
@@ -62,7 +62,7 @@ const contentAndLoadingAdditionalContent = {
const withImmutable = {
id: 'context-dropdown-related-items',
label: 'related immutable items',
- items: Immutable.fromJS([
+ items: fromJS([
{
id: 'context-dropdown-item-document-1',
icon: 'talend-file-json-o',
diff --git a/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.container.js b/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.container.js
index c1907aafce6..dd30c19feba 100644
--- a/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.container.js
+++ b/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.container.js
@@ -1,6 +1,6 @@
import { Component } from 'react';
import PropTypes from 'prop-types';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
export function addPathsToCollection(index, collection, paths, jsonpath) {
return collection.set(index, paths.push(jsonpath));
@@ -16,9 +16,9 @@ export function removePathsFromCollection(index, collection, paths, jsonpath) {
/**
* Collections expandedNodes / collapsedNodes are switched depending of the expand all value.
* @param {number} index
- * @param {Immutable.Map} collection
+ * @param {Map} collection
* @param {boolean} expandAll
- * @param {Immutable.List} paths
+ * @param {List} paths
*/
export function updateCollection(index, collection, expandAll, paths, { opened, jsonpath }) {
if (opened) {
@@ -51,8 +51,8 @@ export default class TreeManager extends Component {
this.state = {
isAllExpanded: props.isAllExpanded || false,
- collapsedNodes: props.collapsedNodes || Immutable.Map(),
- expandedNodes: props.expandedNodes || Immutable.Map().set(0, Immutable.List(['$'])),
+ collapsedNodes: props.collapsedNodes || Map(),
+ expandedNodes: props.expandedNodes || Map().set(0, List(['$'])),
};
}
@@ -88,7 +88,7 @@ export default class TreeManager extends Component {
index,
collection,
isAllExpanded,
- collection.get(index, Immutable.List()),
+ collection.get(index, List()),
options,
),
});
@@ -98,7 +98,7 @@ export default class TreeManager extends Component {
index,
collection,
isAllExpanded,
- collection.get(index, Immutable.List()),
+ collection.get(index, List()),
options,
),
});
diff --git a/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.test.jsx b/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.test.jsx
index a9d4ce332ca..e80045ebaa1 100644
--- a/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.test.jsx
+++ b/packages/components/src/DataViewer/Managers/TreeManager/TreeManager.test.jsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import TreeManager, {
addPathsToCollection,
@@ -9,8 +9,8 @@ import TreeManager, {
describe('addPathsToCollection', () => {
it('should add the jsonpath to the paths collection', () => {
- const myMap = Immutable.Map();
- const myList = Immutable.List();
+ const myMap = Map();
+ const myList = List();
const newMap = addPathsToCollection(0, myMap, myList, 'jsonpath');
expect(newMap.get(0).toJS()).toEqual(['jsonpath']);
});
@@ -18,8 +18,8 @@ describe('addPathsToCollection', () => {
describe('removePathsFromCollection', () => {
it('should remove the jsonpath to the paths collection', () => {
- const myList = Immutable.List(['jsonpath', 'somestuff']);
- const myMap = Immutable.Map({ 0: myList });
+ const myList = List(['jsonpath', 'somestuff']);
+ const myMap = Map({ 0: myList });
const newCollection = removePathsFromCollection(0, myMap, myList, 'jsonpath');
expect(newCollection.get(0).toJS()).toEqual(['somestuff']);
});
diff --git a/packages/components/src/HeaderBar/HeaderBar.stories.jsx b/packages/components/src/HeaderBar/HeaderBar.stories.jsx
index a314d23c18f..7b19978d462 100644
--- a/packages/components/src/HeaderBar/HeaderBar.stories.jsx
+++ b/packages/components/src/HeaderBar/HeaderBar.stories.jsx
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import assetsApi from '@talend/assets-api';
import tokens from '@talend/design-tokens';
import AppSwitcher from '../AppSwitcher';
@@ -102,7 +102,7 @@ export default meta;
export const Default = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
return ;
},
parameters: { info: { styles: infoStyle } },
@@ -110,7 +110,7 @@ export const Default = {
export const WithFullLogo = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.logo.isFull = true;
return ;
},
@@ -119,7 +119,7 @@ export const WithFullLogo = {
export const WithoutProducts = {
render: () => {
- const headerProps = Immutable.fromJS({
+ const headerProps = fromJS({
...props,
products: null,
}).toJS();
@@ -131,7 +131,7 @@ export const WithoutProducts = {
export const WithBrandIcon = {
render: () => {
- const headerProps = Immutable.fromJS({
+ const headerProps = fromJS({
...props,
brand: {
...props.brand,
@@ -145,7 +145,7 @@ export const WithBrandIcon = {
export const WithBrandIconUrl = {
render: () => {
- const headerProps = Immutable.fromJS({
+ const headerProps = fromJS({
...props,
brand: {
...props.brand,
@@ -159,7 +159,7 @@ export const WithBrandIconUrl = {
export const WithEnvironmentDropdown = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.env = {
id: 'header-environment',
items: [
@@ -177,7 +177,7 @@ export const WithEnvironmentDropdown = {
export const WithUnreadNotifications = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.notification = {
hasUnread: true,
};
@@ -188,7 +188,7 @@ export const WithUnreadNotifications = {
export const WithReadNotifications = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.notification = {
hasUnread: false,
};
@@ -199,7 +199,7 @@ export const WithReadNotifications = {
export const WithHelpSplitDropdown = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.help.items = [
{
icon: 'talend-board',
@@ -219,7 +219,7 @@ export const WithHelpSplitDropdown = {
export const WithCallToAction = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.callToAction = {
bsStyle: 'info',
className: 'btn-inverse',
@@ -234,7 +234,7 @@ export const WithCallToAction = {
export const WithGenericAction = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.genericAction = {
bsStyle: 'link',
id: 'header-generic-action',
@@ -249,7 +249,7 @@ export const WithGenericAction = {
export const WithoutUserAndWithInformation = {
render: () => {
- const headerProps = Immutable.fromJS(props).toJS();
+ const headerProps = fromJS(props).toJS();
headerProps.user = null;
headerProps.information = {
id: 'header-info',
diff --git a/packages/components/src/propTypes/immutable.js b/packages/components/src/propTypes/immutable.js
new file mode 100644
index 00000000000..b1831df30e9
--- /dev/null
+++ b/packages/components/src/propTypes/immutable.js
@@ -0,0 +1,28 @@
+// Local copy of immutableListPropType — components does not depend on @talend/react-cmf.
+// Canonical version: packages/cmf/src/propTypes/immutable.js
+// TODO: consider moving these validators to @talend/utils to avoid duplication.
+import { List } from 'immutable';
+
+function immutableListPropType(props, propName, componentName) {
+ if (props[propName] != null && !List.isList(props[propName])) {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected an Immutable.List.`,
+ );
+ }
+ return null;
+}
+
+function makeRequired(validator) {
+ return function isRequired(props, propName, componentName) {
+ if (props[propName] == null) {
+ return new Error(
+ `The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is \`${props[propName]}\`.`,
+ );
+ }
+ return validator(props, propName, componentName);
+ };
+}
+
+immutableListPropType.isRequired = makeRequired(immutableListPropType);
+
+export { immutableListPropType };
diff --git a/packages/components/src/propTypes/immutable.test.js b/packages/components/src/propTypes/immutable.test.js
new file mode 100644
index 00000000000..ffdf2efc887
--- /dev/null
+++ b/packages/components/src/propTypes/immutable.test.js
@@ -0,0 +1,65 @@
+import { List, Map } from 'immutable';
+import { immutableListPropType } from './immutable';
+
+describe('immutableListPropType', () => {
+ it('should return null when prop is an Immutable.List', () => {
+ const props = { items: List() };
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is undefined (optional)', () => {
+ const props = {};
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return null when prop is null (optional)', () => {
+ const props = { items: null };
+ expect(immutableListPropType(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is a plain array', () => {
+ const props = { items: [] };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ expect(result.message).toContain('items');
+ expect(result.message).toContain('TestComponent');
+ expect(result.message).toContain('Immutable.List');
+ });
+
+ it('should return Error when prop is a plain object', () => {
+ const props = { items: {} };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is an Immutable.Map', () => {
+ const props = { items: Map() };
+ const result = immutableListPropType(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
+
+describe('immutableListPropType.isRequired', () => {
+ it('should return Error when prop is undefined', () => {
+ const props = {};
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return Error when prop is null', () => {
+ const props = { items: null };
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+
+ it('should return null when prop is an Immutable.List', () => {
+ const props = { items: List() };
+ expect(immutableListPropType.isRequired(props, 'items', 'TestComponent')).toBeNull();
+ });
+
+ it('should return Error when prop is not an Immutable.List', () => {
+ const props = { items: [] };
+ const result = immutableListPropType.isRequired(props, 'items', 'TestComponent');
+ expect(result).toBeInstanceOf(Error);
+ });
+});
diff --git a/packages/components/src/test-setup.js b/packages/components/src/test-setup.js
index 080c03fe9d7..32ae9bce96d 100644
--- a/packages/components/src/test-setup.js
+++ b/packages/components/src/test-setup.js
@@ -3,6 +3,46 @@ import serializer from 'jest-serializer-html';
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';
+// Node.js v22+ injects a native `localStorage` own data-property on `globalThis`
+// that has no working `setItem`/`getItem` when `--localstorage-file` is not a
+// valid path. In Vitest's jsdom environment `window === globalThis`, so jsdom's
+// own setup cannot override this property.
+//
+// Replace it with a Proxy-backed in-memory store. The Proxy get trap checks
+// `Storage.prototype` at call time so `StorageMock` spies (which patch
+// Storage.prototype) are picked up automatically.
+if (typeof Storage !== 'undefined') {
+ const _data = {};
+ const store = {
+ getItem: key => (Object.prototype.hasOwnProperty.call(_data, key) ? _data[key] : null),
+ setItem: (key, value) => {
+ _data[key] = String(value);
+ },
+ removeItem: key => {
+ delete _data[key];
+ },
+ clear: () => {
+ for (const k of Object.keys(_data)) delete _data[k];
+ },
+ get length() {
+ return Object.keys(_data).length;
+ },
+ key: n => Object.keys(_data)[n] ?? null,
+ };
+ const originals = Object.fromEntries(
+ ['getItem', 'setItem', 'removeItem', 'clear', 'key'].map(n => [n, Storage.prototype[n]]),
+ );
+ globalThis.localStorage = new Proxy(store, {
+ get(target, prop) {
+ if (prop in originals && Storage.prototype[prop] !== originals[prop]) {
+ return Storage.prototype[prop];
+ }
+ const v = target[prop];
+ return typeof v === 'function' ? v.bind(target) : v;
+ },
+ });
+}
+
void i18next.use(initReactI18next).init({
lng: 'en',
fallbackLng: 'en',
diff --git a/packages/components/vitest.config.ts b/packages/components/vitest.config.ts
index 3fd0ac0e11e..f3d3d772100 100644
--- a/packages/components/vitest.config.ts
+++ b/packages/components/vitest.config.ts
@@ -28,6 +28,11 @@ export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
+ environmentOptions: {
+ jsdom: {
+ url: 'http://localhost',
+ },
+ },
setupFiles: ['src/test-setup.js'],
include: ['src/**/*.test.{js,jsx,ts,tsx}'],
exclude: ['lib/**', 'lib-esm/**'],
diff --git a/packages/containers/package.json b/packages/containers/package.json
index 17c2e549199..30f6ee46080 100644
--- a/packages/containers/package.json
+++ b/packages/containers/package.json
@@ -49,11 +49,10 @@
"@talend/react-forms": "^16.1.0",
"@talend/utils": "^3.7.0",
"classnames": "^2.5.1",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"invariant": "^2.2.4",
"lodash": "^4.17.23",
"memoize-one": "^6.0.0",
- "react-immutable-proptypes": "^2.2.0",
"redux-saga": "^1.4.2",
"reselect": "^2.5.4"
},
diff --git a/packages/containers/src/ActionDropdown/ActionDropdown.connect.jsx b/packages/containers/src/ActionDropdown/ActionDropdown.connect.jsx
index 14e8bdd992c..645447192eb 100644
--- a/packages/containers/src/ActionDropdown/ActionDropdown.connect.jsx
+++ b/packages/containers/src/ActionDropdown/ActionDropdown.connect.jsx
@@ -1,6 +1,5 @@
import PropTypes from 'prop-types';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import cmf, { cmfConnect } from '@talend/react-cmf';
+import cmf, { cmfConnect, immutableListPropType } from '@talend/react-cmf';
import { ActionDropdown } from '@talend/react-components/lib/Actions';
import omit from 'lodash/omit';
@@ -50,7 +49,7 @@ export function ContainerActionDropdown({ items, ...props }) {
ContainerActionDropdown.displayName = 'Container(ActionDropdown)';
ContainerActionDropdown.propTypes = {
- items: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), ImmutablePropTypes.list]),
+ items: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), immutableListPropType]),
noCaret: PropTypes.bool,
pullRight: PropTypes.bool,
hideLabel: PropTypes.bool,
diff --git a/packages/containers/src/ActionDropdown/ActionDropdown.stories.jsx b/packages/containers/src/ActionDropdown/ActionDropdown.stories.jsx
index 7acc636b1da..84f05a21bde 100644
--- a/packages/containers/src/ActionDropdown/ActionDropdown.stories.jsx
+++ b/packages/containers/src/ActionDropdown/ActionDropdown.stories.jsx
@@ -1,5 +1,5 @@
/* eslint-disable react/prop-types */
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import { action } from 'storybook/actions';
import ActionDropdown from '.';
@@ -45,7 +45,7 @@ export function Default({ onSelect }) {
displayMode: 'dropdown',
label: 'my immutable items',
onSelect,
- items: Immutable.fromJS([
+ items: fromJS([
{
id: 'item1',
label: 'First immutable label',
diff --git a/packages/containers/src/AppLoader/AppLoader.connect.test.js b/packages/containers/src/AppLoader/AppLoader.connect.test.js
index f2feea27f5a..c5259d1dae7 100644
--- a/packages/containers/src/AppLoader/AppLoader.connect.test.js
+++ b/packages/containers/src/AppLoader/AppLoader.connect.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import { render, screen } from '@testing-library/react';
import { AppLoaderContainer, mapStateToProps } from './AppLoader.connect';
@@ -27,7 +27,7 @@ describe('AppLoader container', () => {
describe('mapStateToProps', () => {
it('should return loading to false if we have nothing to wait', () => {
// given
- const state = { cmf: { collections: Immutable.Map() } };
+ const state = { cmf: { collections: Map() } };
const ownProps = {};
// when
const result = mapStateToProps(state, ownProps);
@@ -37,7 +37,7 @@ describe('AppLoader container', () => {
it('should return loading to true if there is something to wait', () => {
// given
- const state = { cmf: { collections: Immutable.Map({ test2: Immutable.Map() }) } };
+ const state = { cmf: { collections: Map({ test2: Map() }) } };
const ownProps = { hasCollections: ['test', 'test2'] };
// when
const result = mapStateToProps(state, ownProps);
@@ -49,7 +49,7 @@ describe('AppLoader container', () => {
// given
const state = {
cmf: {
- collections: Immutable.Map({ test2: Immutable.Map(), test: Immutable.Map() }),
+ collections: Map({ test2: Map(), test: Map() }),
},
};
const ownProps = { hasCollections: ['test', 'test2'] };
diff --git a/packages/containers/src/ComponentForm/ComponentForm.selectors.test.js b/packages/containers/src/ComponentForm/ComponentForm.selectors.test.js
index a96d2fa17b6..2def53b17b2 100644
--- a/packages/containers/src/ComponentForm/ComponentForm.selectors.test.js
+++ b/packages/containers/src/ComponentForm/ComponentForm.selectors.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import { isComponentFormDirty } from './ComponentForm.selectors';
import { TCompForm } from './ComponentForm.component';
@@ -9,7 +9,7 @@ describe('ComponentForm selectors', () => {
// given
const state = {
cmf: {
- components: Immutable.fromJS({
+ components: fromJS({
[TCompForm.displayName]: {
[componentName]: {},
},
@@ -26,7 +26,7 @@ describe('ComponentForm selectors', () => {
// given
const state = {
cmf: {
- components: Immutable.fromJS({
+ components: fromJS({
[TCompForm.displayName]: {
[componentName]: { dirty: false },
},
@@ -43,7 +43,7 @@ describe('ComponentForm selectors', () => {
// given
const state = {
cmf: {
- components: Immutable.fromJS({
+ components: fromJS({
[TCompForm.displayName]: {
[componentName]: { dirty: true },
},
diff --git a/packages/containers/src/DeleteResource/DeleteResource.connect.js b/packages/containers/src/DeleteResource/DeleteResource.connect.js
index 6f3970497e1..8c4e24a07cb 100644
--- a/packages/containers/src/DeleteResource/DeleteResource.connect.js
+++ b/packages/containers/src/DeleteResource/DeleteResource.connect.js
@@ -1,5 +1,5 @@
import { cmfConnect } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import get from 'lodash/get';
import Container from './DeleteResource.container';
@@ -17,7 +17,7 @@ export function mapStateToProps(state, ownProps) {
const collectionId = ownProps.collectionId || ownProps.resourceType;
if (collectionId) {
props.resource = state.cmf.collections
- .get(collectionId, new Immutable.Map())
+ .get(collectionId, new Map())
.find(currentResource => currentResource.get('id') === resourceId);
}
}
diff --git a/packages/containers/src/DeleteResource/DeleteResource.test.js b/packages/containers/src/DeleteResource/DeleteResource.test.js
index e57643bbf4b..bbcc53c5613 100644
--- a/packages/containers/src/DeleteResource/DeleteResource.test.js
+++ b/packages/containers/src/DeleteResource/DeleteResource.test.js
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import cmf, { mock } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import { DeleteResource } from './DeleteResource.container';
import Connected, { mapStateToProps } from './DeleteResource.connect';
@@ -10,8 +10,8 @@ const settings = {};
state.cmf = {
settings,
};
-state.cmf.collections = new Immutable.Map({
- foo: new Immutable.List([new Immutable.Map({ id: '123' })]),
+state.cmf.collections = new Map({
+ foo: new List([new Map({ id: '123' })]),
});
describe('Container DeleteResource', () => {
@@ -27,7 +27,7 @@ describe('Container DeleteResource', () => {
const props = {
uri: '/myEndpoint',
resourceType: 'myResourceType',
- resource: new Immutable.Map({ label: 'myLabel' }),
+ resource: new Map({ label: 'myLabel' }),
header: 'My header title',
params: { id: 'myResourceID' },
resourceTypeLabel: 'resourceLabel',
diff --git a/packages/containers/src/EditableText/EditableText.container.jsx b/packages/containers/src/EditableText/EditableText.container.jsx
index 7a46fb2a420..ccd69a298d7 100644
--- a/packages/containers/src/EditableText/EditableText.container.jsx
+++ b/packages/containers/src/EditableText/EditableText.container.jsx
@@ -1,12 +1,12 @@
import { Component as RComponent } from 'react';
import PropTypes from 'prop-types';
import Component from '@talend/react-components/lib/EditableText';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import omit from 'lodash/omit';
import { cmfConnect } from '@talend/react-cmf';
export const DISPLAY_NAME = 'Container(EditableText)';
-export const DEFAULT_STATE = new Immutable.Map({
+export const DEFAULT_STATE = new Map({
editMode: false,
});
diff --git a/packages/containers/src/FilterBar/FilterBar.container.jsx b/packages/containers/src/FilterBar/FilterBar.container.jsx
index 34f1d6d4e03..ba2214eed2f 100644
--- a/packages/containers/src/FilterBar/FilterBar.container.jsx
+++ b/packages/containers/src/FilterBar/FilterBar.container.jsx
@@ -2,11 +2,11 @@ import { cmfConnect } from '@talend/react-cmf';
import { Component as RComponent } from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import Component from '@talend/react-components/lib/FilterBar';
export const QUERY_ATTR = 'query';
-export const DEFAULT_STATE = new Immutable.Map({
+export const DEFAULT_STATE = new Map({
[QUERY_ATTR]: '',
docked: true,
});
diff --git a/packages/containers/src/Form/Form.container.jsx b/packages/containers/src/Form/Form.container.jsx
index a3d5747e35f..0f4e0bc0545 100644
--- a/packages/containers/src/Form/Form.container.jsx
+++ b/packages/containers/src/Form/Form.container.jsx
@@ -1,6 +1,6 @@
import { Component } from 'react';
import PropTypes from 'prop-types';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import { cmfConnect } from '@talend/react-cmf';
import BaseForm from '@talend/react-forms';
import classnames from 'classnames';
@@ -10,7 +10,7 @@ if (process.env.FORM_MOZ) {
DefaultArrayFieldTemplate = BaseForm.deprecated.templates.ArrayFieldTemplate;
}
-export const DEFAULT_STATE = new Immutable.Map({});
+export const DEFAULT_STATE = new Map({});
/**
* Because we don't want to loose form input
@@ -42,7 +42,7 @@ class Form extends Component {
* @return {[type]} [description]
*/
static getFormData(state, formId) {
- return state.cmf.components.getIn(['Container(Form)', formId, 'data'], new Immutable.Map());
+ return state.cmf.components.getIn(['Container(Form)', formId, 'data'], new Map());
}
static getDerivedStateFromProps(nextProps, prevState) {
diff --git a/packages/containers/src/HomeListView/HomeListView.stories.jsx b/packages/containers/src/HomeListView/HomeListView.stories.jsx
index 472c69b8f7e..a70a0e4a2da 100644
--- a/packages/containers/src/HomeListView/HomeListView.stories.jsx
+++ b/packages/containers/src/HomeListView/HomeListView.stories.jsx
@@ -1,6 +1,6 @@
import { Drawer } from '@talend/react-components';
import { action } from 'storybook/actions';
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import HomeListView from '.';
@@ -128,7 +128,7 @@ const toolbar = {
},
};
-const items = Immutable.fromJS([
+const items = fromJS([
{
id: 1,
label: 'Title with actions',
diff --git a/packages/containers/src/List/List.container.jsx b/packages/containers/src/List/List.container.jsx
index f0d715322ae..a2058feb011 100644
--- a/packages/containers/src/List/List.container.jsx
+++ b/packages/containers/src/List/List.container.jsx
@@ -1,12 +1,11 @@
import PropTypes from 'prop-types';
-import ImmutablePropTypes from 'react-immutable-proptypes';
import { Map, List as ImmutableList } from 'immutable';
import Component from '@talend/react-components/lib/List';
import VirtualizedList from '@talend/react-components/lib/VirtualizedList';
import get from 'lodash/get';
import omit from 'lodash/omit';
import pick from 'lodash/pick';
-import cmf, { cmfConnect, useCMFContext } from '@talend/react-cmf';
+import cmf, { cmfConnect, useCMFContext, immutableListPropType } from '@talend/react-cmf';
import { getActionsProps } from '../actionAPI';
import Constants from './List.constant';
@@ -353,7 +352,7 @@ List.propTypes = {
}),
cellDictionary: PropTypes.object,
displayMode: PropTypes.string,
- items: ImmutablePropTypes.list.isRequired,
+ items: immutableListPropType.isRequired,
state: cmfConnect.propTypes.state,
...cmfConnect.propTypes,
};
diff --git a/packages/containers/src/List/List.stories.jsx b/packages/containers/src/List/List.stories.jsx
index bd3f759b262..917966ee865 100644
--- a/packages/containers/src/List/List.stories.jsx
+++ b/packages/containers/src/List/List.stories.jsx
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import api from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { Map, fromJS } from 'immutable';
import cloneDeep from 'lodash/cloneDeep';
import List from '.';
@@ -115,16 +115,16 @@ const customHeight = {
table: 100,
};
-const defaultListState = new Immutable.Map({
+const defaultListState = new Map({
displayMode: 'large',
});
-const defaultSortedListState = new Immutable.Map({
+const defaultSortedListState = new Map({
sortOn: 'modified',
sortAsc: false,
});
-const items = Immutable.fromJS([
+const items = fromJS([
{
id: 'id1',
label: 'Title with actions',
@@ -189,7 +189,7 @@ const minusThreeMin = referenceDatetime - 60 * 3 * 1000;
const oneDay = 24 * 3600 * 1000;
-const itemsWithTimestamp = Immutable.fromJS([
+const itemsWithTimestamp = fromJS([
{
id: 'id0',
label: 'Title with actions but first',
@@ -259,7 +259,7 @@ export const WithSeparatorActions = () => (
export const Pagination = () => {
const propsPg = cloneDeep(props);
const itemsPg = items.concat(
- Immutable.fromJS([
+ fromJS([
{
id: 'id4',
label: 'Title with actions',
diff --git a/packages/containers/src/Notification/Notification.sagas.test.js b/packages/containers/src/Notification/Notification.sagas.test.js
index e26a0a4db47..9e35821e155 100644
--- a/packages/containers/src/Notification/Notification.sagas.test.js
+++ b/packages/containers/src/Notification/Notification.sagas.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import { runSaga } from 'redux-saga';
import { onPushNotification } from './Notification.sagas';
@@ -18,7 +18,7 @@ describe('Notification sagas', () => {
dispatch: a => dispatched.push(a),
getState: () => ({
cmf: {
- components: Immutable.fromJS({
+ components: fromJS({
'Container(Notification)': {
Notification: {
notifications: [],
@@ -33,7 +33,7 @@ describe('Notification sagas', () => {
).done;
// Convert first, the half immutable payload to a full one then back to a full js one
- const actions = Immutable.fromJS(dispatched).toJS();
+ const actions = fromJS(dispatched).toJS();
expect(actions[0]).toEqual({
type: 'Container(Notification).setState',
diff --git a/packages/containers/src/Notification/Notification.test.jsx b/packages/containers/src/Notification/Notification.test.jsx
index c38ad6f2e6b..3e9adde11d3 100644
--- a/packages/containers/src/Notification/Notification.test.jsx
+++ b/packages/containers/src/Notification/Notification.test.jsx
@@ -3,7 +3,7 @@
/* eslint-disable react/display-name */
import { render } from '@testing-library/react';
import { mock } from '@talend/react-cmf';
-import Immutable, { fromJS } from 'immutable';
+import { Map, fromJS } from 'immutable';
// eslint-disable-next-line @talend/import-depth
import { prepareCMF } from '@talend/react-cmf/lib/mock/rtl';
import Container from './Notification.container';
@@ -89,7 +89,7 @@ describe('Notification.pushNotification', () => {
it('should add a Notification in the state even if the state slot is not yet available', () => {
const state = mock.store.state();
- state.cmf.components = new Immutable.Map();
+ state.cmf.components = new Map();
const notification = { message: 'hello world' };
const newState = pushNotification(state, notification);
const notifications = newState.cmf.components.getIn([
diff --git a/packages/containers/src/Notification/pushNotification.js b/packages/containers/src/Notification/pushNotification.js
index 3e8e51ca99c..b2fe3b710cc 100644
--- a/packages/containers/src/Notification/pushNotification.js
+++ b/packages/containers/src/Notification/pushNotification.js
@@ -1,5 +1,5 @@
import get from 'lodash/get';
-import Immutable from 'immutable';
+import { List } from 'immutable';
import { randomUUID } from '@talend/utils';
/**
@@ -14,7 +14,7 @@ export default function pushNotification(state, notification) {
return state;
}
const path = ['Container(Notification)', 'Notification', 'notifications'];
- let notifs = state.cmf.components.getIn(path, new Immutable.List());
+ let notifs = state.cmf.components.getIn(path, new List());
notifs = notifs.push({
id: randomUUID(),
...notification,
diff --git a/packages/containers/src/PieChartButton/PieChartButton.connect.jsx b/packages/containers/src/PieChartButton/PieChartButton.connect.jsx
index 2d908461d60..af372ac9728 100644
--- a/packages/containers/src/PieChartButton/PieChartButton.connect.jsx
+++ b/packages/containers/src/PieChartButton/PieChartButton.connect.jsx
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import omit from 'lodash/omit';
import { cmfConnect, Inject } from '@talend/react-cmf';
import PieChart from '@talend/react-components/lib/PieChart';
-export const DEFAULT_STATE = new Immutable.Map({});
+export const DEFAULT_STATE = new Map({});
export function ContainerPieChartButton(props) {
let overlayComponent = null;
diff --git a/packages/containers/src/PieChartButton/PieChartButton.test.js b/packages/containers/src/PieChartButton/PieChartButton.test.js
index f2e7d72dc0d..54a511c4b83 100644
--- a/packages/containers/src/PieChartButton/PieChartButton.test.js
+++ b/packages/containers/src/PieChartButton/PieChartButton.test.js
@@ -1,4 +1,4 @@
-import Immutable from 'immutable';
+import { fromJS } from 'immutable';
import { screen, render } from '@testing-library/react';
import Connected, { ContainerPieChartButton } from './PieChartButton.connect';
@@ -11,7 +11,7 @@ describe('PieChartButton connected', () => {
describe('PieChartButton container', () => {
it('should render', () => {
- const initialState = Immutable.fromJS({
+ const initialState = fromJS({
model: [
{ percentage: 10, color: 'rio-grande' },
{ percentage: 15, color: 'chestnut-rose' },
@@ -25,7 +25,7 @@ describe('PieChartButton container', () => {
});
it('should render not available pie chart button', () => {
- const initialState = Immutable.fromJS({
+ const initialState = fromJS({
model: [
{ percentage: 10, color: 'rio-grande' },
{ percentage: 15, color: 'chestnut-rose' },
@@ -40,7 +40,7 @@ describe('PieChartButton container', () => {
});
it('should render loading pie chart button', () => {
- const initialState = Immutable.fromJS({
+ const initialState = fromJS({
model: [
{ percentage: 10, color: 'rio-grande' },
{ percentage: 15, color: 'chestnut-rose' },
diff --git a/packages/containers/src/SelectObject/SelectObject.component.jsx b/packages/containers/src/SelectObject/SelectObject.component.jsx
index acd7c66d523..b4caec666e9 100644
--- a/packages/containers/src/SelectObject/SelectObject.component.jsx
+++ b/packages/containers/src/SelectObject/SelectObject.component.jsx
@@ -1,4 +1,4 @@
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import { immutableListPropType } from '@talend/react-cmf';
import classNames from 'classnames';
import PropTypes from 'prop-types';
@@ -80,12 +80,12 @@ SelectObject.propTypes = {
list: PropTypes.object,
filter: PropTypes.object,
schema: PropTypes.object,
- filteredData: ImmutablePropTypes.List,
+ filteredData: immutableListPropType,
results: PropTypes.shape({
selectedId: PropTypes.string,
onClick: PropTypes.func,
}),
- sourceData: ImmutablePropTypes.List,
+ sourceData: immutableListPropType,
selected: PropTypes.object,
};
diff --git a/packages/containers/src/SelectObject/SelectObject.component.test.js b/packages/containers/src/SelectObject/SelectObject.component.test.js
index 3a7421577e8..c9007a7ba08 100644
--- a/packages/containers/src/SelectObject/SelectObject.component.test.js
+++ b/packages/containers/src/SelectObject/SelectObject.component.test.js
@@ -1,13 +1,13 @@
import { render } from '@testing-library/react';
import { mock } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import Component from './SelectObject.component';
describe('Component SelectObject', () => {
it('should render', () => {
const context = mock.store.context();
- const item = new Immutable.Map({ id: '1', name: 'foo' });
+ const item = new Map({ id: '1', name: 'foo' });
const props = {
id: 'my-tree',
schema: {
@@ -21,7 +21,7 @@ describe('Component SelectObject', () => {
},
},
},
- sourceData: new Immutable.List([item]),
+ sourceData: new List([item]),
filter: {
className: 'my-custom-filter',
},
diff --git a/packages/containers/src/SelectObject/SelectObject.connect.test.js b/packages/containers/src/SelectObject/SelectObject.connect.test.js
index 46cc330f9e3..bc83a6f4c5f 100644
--- a/packages/containers/src/SelectObject/SelectObject.connect.test.js
+++ b/packages/containers/src/SelectObject/SelectObject.connect.test.js
@@ -1,5 +1,5 @@
import { mock } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import Container from './SelectObject.container';
import Connected, { mapStateToProps } from './SelectObject.connect';
@@ -11,19 +11,16 @@ describe('Connected SelectObject', () => {
});
it('should map state to props', () => {
const state = mock.store.state();
- const data = new Immutable.List([
- new Immutable.Map({ label: 'foo' }),
- new Immutable.Map({ label: 'bar' }),
- ]);
- state.cmf.collections = new Immutable.Map({
- width: new Immutable.Map({ data }),
+ const data = new List([new Map({ label: 'foo' }), new Map({ label: 'bar' })]);
+ state.cmf.collections = new Map({
+ width: new Map({ data }),
});
- state.cmf.components = new Immutable.Map({
- 'Container(FilterBar)': new Immutable.Map({
- test: new Immutable.Map({ query: 'foo' }),
+ state.cmf.components = new Map({
+ 'Container(FilterBar)': new Map({
+ test: new Map({ query: 'foo' }),
}),
- 'Container(Tree)': new Immutable.Map({
- test: new Immutable.Map({ selectedId: '27' }),
+ 'Container(Tree)': new Map({
+ test: new Map({ selectedId: '27' }),
}),
});
const props = mapStateToProps(state, {
diff --git a/packages/containers/src/SelectObject/SelectObject.container.jsx b/packages/containers/src/SelectObject/SelectObject.container.jsx
index d5d7c00e3f7..779d7db747f 100644
--- a/packages/containers/src/SelectObject/SelectObject.container.jsx
+++ b/packages/containers/src/SelectObject/SelectObject.container.jsx
@@ -2,12 +2,12 @@ import { Component as RComponent } from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import { cmfConnect } from '@talend/react-cmf';
-import Immutable, { List } from 'immutable';
+import { List, Map } from 'immutable';
import Component from './SelectObject.component';
export const DISPLAY_NAME = 'Container(SelectObject)';
-export const DEFAULT_STATE = new Immutable.Map({});
+export const DEFAULT_STATE = new Map({});
function noop() {}
@@ -142,7 +142,7 @@ class SelectObject extends RComponent {
};
static defaultProps = {
- sourceData: new Immutable.List(),
+ sourceData: new List(),
idAttr: 'id',
nameAttr: 'name',
breadCrumbsRootLabel: 'root',
diff --git a/packages/containers/src/SelectObject/SelectObject.container.test.jsx b/packages/containers/src/SelectObject/SelectObject.container.test.jsx
index 8b032b4c6d6..78327fa1450 100644
--- a/packages/containers/src/SelectObject/SelectObject.container.test.jsx
+++ b/packages/containers/src/SelectObject/SelectObject.container.test.jsx
@@ -2,7 +2,7 @@
/* eslint-disable react/display-name */
import { screen, render, fireEvent } from '@testing-library/react';
import { mock } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { List, Map, fromJS } from 'immutable';
// eslint-disable-next-line @talend/import-depth
import { prepareCMF } from '@talend/react-cmf/lib/mock/rtl';
@@ -29,8 +29,8 @@ describe('Container SelectObject', () => {
it('should default props with Tree map the selectedId', async () => {
const tree = {};
const getProps = jest.fn();
- const item = new Immutable.Map({ id: '1', name: 'foo' });
- const sourceData = new Immutable.List([item]);
+ const item = new Map({ id: '1', name: 'foo' });
+ const sourceData = new List([item]);
render(
await prepareCMF(
,
@@ -45,7 +45,7 @@ describe('Container SelectObject', () => {
preview: undefined,
selected: item.toJS(),
selectedId: '1',
- sourceData: new Immutable.List([item]),
+ sourceData: new List([item]),
tree: {
onSelect: expect.anything(),
selectedId: '1',
@@ -55,9 +55,9 @@ describe('Container SelectObject', () => {
it('should set selectedId props to the only matched item if nothing selected', async () => {
const getProps = jest.fn();
const tree = {};
- const item1 = new Immutable.Map({ id: '1', name: 'foo' });
- const item2 = new Immutable.Map({ id: '2', name: 'bar' });
- const sourceData = new Immutable.List([item1, item2]);
+ const item1 = new Map({ id: '1', name: 'foo' });
+ const item2 = new Map({ id: '2', name: 'bar' });
+ const sourceData = new List([item1, item2]);
render(
await prepareCMF(
@@ -73,7 +73,7 @@ describe('Container SelectObject', () => {
query: 'f',
selected: item1.toJS(),
sourceData,
- filteredData: expect.any(Immutable.List),
+ filteredData: expect.any(List),
results: {
idAttr: 'id',
nameAttr: 'name',
@@ -99,7 +99,7 @@ describe('Container SelectObject', () => {
});
it('should call filter and getById', () => {
const props = {
- sourceData: new Immutable.List(),
+ sourceData: new List(),
query: 'query',
selectedId: 1,
};
@@ -113,18 +113,18 @@ describe('Container SelectObject', () => {
describe('getById', () => {
it('should return nothing if not found and POO if found', () => {
- const subfirst = new Immutable.Map({ id: 11 });
- const first = new Immutable.Map({ id: 1, children: new Immutable.List([subfirst]) });
- const second = new Immutable.Map({ id: 2 });
- const items = new Immutable.List([first, second]);
+ const subfirst = new Map({ id: 11 });
+ const first = new Map({ id: 1, children: new List([subfirst]) });
+ const second = new Map({ id: 2 });
+ const items = new List([first, second]);
expect(getById(items, 11)).toEqual({ id: 11 });
expect(getById(items, 3)).toBe();
});
it('should return be able to support some options', () => {
- const subfirst = new Immutable.Map({ myid: 11 });
- const first = new Immutable.Map({ myid: 1, children: new Immutable.List([subfirst]) });
- const second = new Immutable.Map({ myid: 2 });
- const items = new Immutable.List([first, second]);
+ const subfirst = new Map({ myid: 11 });
+ const first = new Map({ myid: 1, children: new List([subfirst]) });
+ const second = new Map({ myid: 2 });
+ const items = new List([first, second]);
expect(getById(items, 11, { idAttr: 'myid' })).toEqual({ myid: 11 });
expect(getById(items, 3)).toBe();
});
@@ -132,14 +132,14 @@ describe('Container SelectObject', () => {
describe('filter', () => {
it('does not match on non leaf element (non leaf element have children)', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub' });
- const first = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst]),
+ children: new List([subfirst]),
});
- const second = new Immutable.Map({ id: 2, name: 'foo' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'foo' });
+ const items = new List([first, second]);
// when
const results = filter(items, 'ab');
@@ -149,14 +149,14 @@ describe('Container SelectObject', () => {
});
it('does match only on leaf element', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub' });
- const first = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst]),
+ children: new List([subfirst]),
});
- const second = new Immutable.Map({ id: 2, name: 'foo' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'foo' });
+ const items = new List([first, second]);
// when
const results = filter(items, 'sub');
@@ -170,14 +170,14 @@ describe('Container SelectObject', () => {
});
it('does match on multiple leaf elements of different depth, result is list', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub' });
- const first = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst]),
+ children: new List([subfirst]),
});
- const second = new Immutable.Map({ id: 2, name: 'sub' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'sub' });
+ const items = new List([first, second]);
// when
const results = filter(items, 'sub');
@@ -195,20 +195,20 @@ describe('Container SelectObject', () => {
it('does match on multiple leaf children of a node', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub1' });
- const subsecond = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub1' });
+ const subsecond = new Map({
id: 12,
name: 'sub2',
- children: new Immutable.List([Immutable.Map()]),
+ children: new List([Map()]),
});
- const subthird = new Immutable.Map({ id: 13, name: 'sub3' });
- const first = new Immutable.Map({
+ const subthird = new Map({ id: 13, name: 'sub3' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst, subsecond, subthird]),
+ children: new List([subfirst, subsecond, subthird]),
});
- const second = new Immutable.Map({ id: 2, name: 'sub' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'sub' });
+ const items = new List([first, second]);
// when
const results = filter(items, 'sub');
@@ -229,19 +229,19 @@ describe('Container SelectObject', () => {
it('does match on multiple leaf children of different node', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub1' });
- const subsecond = new Immutable.Map({ id: 13, name: 'sub2' });
- const first = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub1' });
+ const subsecond = new Map({ id: 13, name: 'sub2' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst]),
+ children: new List([subfirst]),
});
- const second = new Immutable.Map({
+ const second = new Map({
id: 2,
name: 'sub',
- children: new Immutable.List([subsecond]),
+ children: new List([subsecond]),
});
- const items = new Immutable.List([first, second]);
+ const items = new List([first, second]);
// when
const results = filter(items, 'sub');
@@ -259,20 +259,20 @@ describe('Container SelectObject', () => {
it('return the original struct if no query or empty query is provided', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub1' });
- const subsecond = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub1' });
+ const subsecond = new Map({
id: 12,
name: 'sub2',
- children: new Immutable.List([Immutable.Map()]),
+ children: new List([Map()]),
});
- const subthird = new Immutable.Map({ id: 13, name: 'sub3' });
- const first = new Immutable.Map({
+ const subthird = new Map({ id: 13, name: 'sub3' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst, subsecond, subthird]),
+ children: new List([subfirst, subsecond, subthird]),
});
- const second = new Immutable.Map({ id: 2, name: 'sub' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'sub' });
+ const items = new List([first, second]);
// when
const results = filter(items, '');
@@ -309,7 +309,7 @@ describe('Container SelectObject', () => {
},
];
- const items = Immutable.fromJS(tree);
+ const items = fromJS(tree);
const results = filterAll(items, 'ab');
expect(results.size).toBe(3);
@@ -325,14 +325,14 @@ describe('Container SelectObject', () => {
it('does match on multiple leaf elements of different depth, result is list', () => {
// given
- const subfirst = new Immutable.Map({ id: 11, name: 'sub' });
- const first = new Immutable.Map({
+ const subfirst = new Map({ id: 11, name: 'sub' });
+ const first = new Map({
id: 1,
name: 'abc',
- children: new Immutable.List([subfirst]),
+ children: new List([subfirst]),
});
- const second = new Immutable.Map({ id: 2, name: 'sub' });
- const items = new Immutable.List([first, second]);
+ const second = new Map({ id: 2, name: 'sub' });
+ const items = new List([first, second]);
// when
const results = filter(items, 'sub');
diff --git a/packages/containers/src/Slider/Slider.container.jsx b/packages/containers/src/Slider/Slider.container.jsx
index e2b6c7db968..f4f4bc2a37f 100644
--- a/packages/containers/src/Slider/Slider.container.jsx
+++ b/packages/containers/src/Slider/Slider.container.jsx
@@ -2,11 +2,11 @@ import { Component as RComponent } from 'react';
import { cmfConnect } from '@talend/react-cmf';
import Component from '@talend/react-components/lib/Slider';
import omit from 'lodash/omit';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import PropTypes from 'prop-types';
export const VALUE_ATTR = 'value';
-export const DEFAULT_STATE = new Immutable.Map({
+export const DEFAULT_STATE = new Map({
[VALUE_ATTR]: undefined,
});
diff --git a/packages/containers/src/SubHeaderBar/SubHeaderBar.container.jsx b/packages/containers/src/SubHeaderBar/SubHeaderBar.container.jsx
index 5b577857231..05b9bdd6ad2 100644
--- a/packages/containers/src/SubHeaderBar/SubHeaderBar.container.jsx
+++ b/packages/containers/src/SubHeaderBar/SubHeaderBar.container.jsx
@@ -1,12 +1,12 @@
import { Component as RComponent } from 'react';
import PropTypes from 'prop-types';
import Component from '@talend/react-components/lib/SubHeaderBar';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import omit from 'lodash/omit';
import { cmfConnect } from '@talend/react-cmf';
export const DISPLAY_NAME = 'Container(SubHeaderBar)';
-export const DEFAULT_STATE = new Immutable.Map({});
+export const DEFAULT_STATE = new Map({});
class SubHeaderBar extends RComponent {
static displayName = DISPLAY_NAME;
diff --git a/packages/containers/src/TabBar/TabBar.connect.js b/packages/containers/src/TabBar/TabBar.connect.js
index 35cfb527c7a..561cb41cd94 100644
--- a/packages/containers/src/TabBar/TabBar.connect.js
+++ b/packages/containers/src/TabBar/TabBar.connect.js
@@ -1,8 +1,8 @@
import { cmfConnect } from '@talend/react-cmf';
import TabBar from '@talend/react-components/lib/TabBar';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
-export const DEFAULT_STATE = new Immutable.Map({});
+export const DEFAULT_STATE = new Map({});
export default cmfConnect({
componentId: ownProps => ownProps.componentId || ownProps.id,
diff --git a/packages/containers/src/TreeView/TreeView.container.jsx b/packages/containers/src/TreeView/TreeView.container.jsx
index 50576e8990e..cd1c3188e45 100644
--- a/packages/containers/src/TreeView/TreeView.container.jsx
+++ b/packages/containers/src/TreeView/TreeView.container.jsx
@@ -1,9 +1,8 @@
import { Component as RComponent } from 'react';
import PropTypes from 'prop-types';
-import { cmfConnect } from '@talend/react-cmf';
+import { cmfConnect, immutableListPropType } from '@talend/react-cmf';
import Component from '@talend/react-components/lib/TreeView';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import omit from 'lodash/omit';
const OPENED_ATTR = 'opened';
@@ -14,8 +13,8 @@ export const DEFAULT_PROPS = {
nameAttr: 'name',
childrenAttr: 'children',
};
-export const DEFAULT_STATE = new Immutable.Map({
- [OPENED_ATTR]: new Immutable.List(),
+export const DEFAULT_STATE = new Map({
+ [OPENED_ATTR]: new List(),
[SELECTED_ATTR]: undefined,
});
@@ -103,7 +102,7 @@ class TreeView extends RComponent {
static propTypes = {
childrenAttr: PropTypes.string,
- data: ImmutablePropTypes.list,
+ data: immutableListPropType,
idAttr: PropTypes.string,
nameAttr: PropTypes.string,
onClick: PropTypes.func,
diff --git a/packages/containers/src/TreeView/TreeView.test.js b/packages/containers/src/TreeView/TreeView.test.js
index 009c5bf7807..876d79cdf40 100644
--- a/packages/containers/src/TreeView/TreeView.test.js
+++ b/packages/containers/src/TreeView/TreeView.test.js
@@ -1,6 +1,6 @@
import { screen, render, fireEvent } from '@testing-library/react';
import { mock } from '@talend/react-cmf';
-import Immutable from 'immutable';
+import { List, Map } from 'immutable';
import TreeView, {
DEFAULT_STATE,
DEFAULT_PROPS,
@@ -16,9 +16,9 @@ describe('TreeView', () => {
beforeEach(() => {
context = mock.store.context();
state = mock.store.state();
- data = new Immutable.List([
- new Immutable.Map({ id: 1, name: 'foo', children: [{ id: 11, name: 'fofo', childre: [] }] }),
- new Immutable.Map({ id: 2, name: 'bar', children: [] }),
+ data = new List([
+ new Map({ id: 1, name: 'foo', children: [{ id: 11, name: 'fofo', childre: [] }] }),
+ new Map({ id: 2, name: 'bar', children: [] }),
]);
context.store.getState = () => state;
});
@@ -161,9 +161,9 @@ describe('TreeView', () => {
describe('mapStateToProps', () => {
it('should return props', () => {
const state = mock.store.state();
- const data = new Immutable.Map({
- foo: new Immutable.Map({
- bar: new Immutable.List([new Immutable.Map({ foo: 'bar' })]),
+ const data = new Map({
+ foo: new Map({
+ bar: new List([new Map({ foo: 'bar' })]),
}),
});
state.cmf.collections = state.cmf.collections.set('data', data);
@@ -180,8 +180,8 @@ describe('transform', () => {
it('should add toggled booleans', () => {
const props = {
...DEFAULT_PROPS,
- state: Immutable.Map({
- opened: Immutable.List([1, 11, 111]),
+ state: Map({
+ opened: List([1, 11, 111]),
selectedId: 11,
}),
};
@@ -212,8 +212,8 @@ describe('transform', () => {
it("should unfold selected's parents", () => {
const props = {
...DEFAULT_PROPS,
- state: Immutable.Map({
- opened: Immutable.List([1, 11, 111]),
+ state: Map({
+ opened: List([1, 11, 111]),
selectedId: 111,
}),
};
diff --git a/packages/containers/src/Typeahead/Typeahead.container.jsx b/packages/containers/src/Typeahead/Typeahead.container.jsx
index a4428c53407..865c6374bf4 100644
--- a/packages/containers/src/Typeahead/Typeahead.container.jsx
+++ b/packages/containers/src/Typeahead/Typeahead.container.jsx
@@ -1,6 +1,6 @@
import { Component as RComponent } from 'react';
-import Immutable from 'immutable';
+import { Map } from 'immutable';
import omit from 'lodash/omit';
import PropTypes from 'prop-types';
@@ -8,7 +8,7 @@ import { cmfConnect, componentState } from '@talend/react-cmf';
import Component from '@talend/react-components/lib/Typeahead';
export const DISPLAY_NAME = 'Container(Typeahead)';
-export const DEFAULT_STATE = new Immutable.Map({
+export const DEFAULT_STATE = new Map({
docked: true,
searching: false,
focusedSectionIndex: null,
diff --git a/packages/flow-designer/package.json b/packages/flow-designer/package.json
index 318abb1d9c4..47d7713cc5a 100644
--- a/packages/flow-designer/package.json
+++ b/packages/flow-designer/package.json
@@ -53,7 +53,7 @@
"@types/redux-thunk": "^2.1.0",
"eslint": "^9.39.3",
"i18next": "^23.16.8",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"lodash": "^4.17.23",
"prop-types": "^15.8.1",
"react": "^18.3.1",
@@ -68,7 +68,7 @@
"vitest": "^4.0.18"
},
"peerDependencies": {
- "immutable": "3",
+ "immutable": "^5.0.0",
"lodash": "^4.17.23",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -81,8 +81,7 @@
"classnames": "^2.5.1",
"d3": "^7.9.0",
"invariant": "^2.2.4",
- "prop-types": "^15.8.1",
- "react-immutable-proptypes": "^2.2.0"
+ "prop-types": "^15.8.1"
},
"files": [
"/dist",
diff --git a/packages/flow-designer/src/actions/node.actions.test.ts b/packages/flow-designer/src/actions/node.actions.test.ts
index a0b4212b746..48b7f44aa22 100644
--- a/packages/flow-designer/src/actions/node.actions.test.ts
+++ b/packages/flow-designer/src/actions/node.actions.test.ts
@@ -1,7 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
-import { Map, OrderedMap } from 'immutable';
+import { Map } from 'immutable';
import * as nodeActions from './node.actions';
import { FLOWDESIGNER_NODE_SET_TYPE } from '../constants/flowdesigner.constants';
@@ -41,7 +41,7 @@ describe('Check that node action creators generate proper action objects and per
}),
}),
// eslint-disable-next-line new-cap
- ports: OrderedMap(),
+ ports: Map(),
},
});
diff --git a/packages/flow-designer/src/components/link/LinksRenderer.component.tsx b/packages/flow-designer/src/components/link/LinksRenderer.component.tsx
index 62c0199aeac..9c44aa768d9 100644
--- a/packages/flow-designer/src/components/link/LinksRenderer.component.tsx
+++ b/packages/flow-designer/src/components/link/LinksRenderer.component.tsx
@@ -9,7 +9,7 @@ type Props = {
class LinksRender extends Component {
render() {
- const links = this.props.links.toArray();
+ const links = this.props.links.valueSeq().toArray();
return (
{links.map(link => {
diff --git a/packages/flow-designer/src/components/link/LinksRenderer.test.tsx b/packages/flow-designer/src/components/link/LinksRenderer.test.tsx
index cdef1674dd0..d2c1d046782 100644
--- a/packages/flow-designer/src/components/link/LinksRenderer.test.tsx
+++ b/packages/flow-designer/src/components/link/LinksRenderer.test.tsx
@@ -1,6 +1,6 @@
/* eslint-disable new-cap */
import renderer from 'react-test-renderer';
-import { Map, OrderedMap } from 'immutable';
+import { Map } from 'immutable';
import LinksRenderer from './LinksRenderer.component';
import { LinkRecord, PortRecord, PositionRecord } from '../../constants/flowdesigner.model';
@@ -25,7 +25,7 @@ describe('', () => {
}),
}),
);
- const ports = OrderedMap()
+ const ports = Map()
.set(
'port1',
new PortRecord({
diff --git a/packages/flow-designer/src/components/node/NodesRenderer.component.tsx b/packages/flow-designer/src/components/node/NodesRenderer.component.tsx
index 42677a5700c..c5b29a5fcd1 100644
--- a/packages/flow-designer/src/components/node/NodesRenderer.component.tsx
+++ b/packages/flow-designer/src/components/node/NodesRenderer.component.tsx
@@ -41,7 +41,7 @@ class NodesRenderer extends Component {
}
render() {
- return {this.props.nodes.toArray().map(this.renderNode)};
+ return {this.props.nodes.valueSeq().toArray().map(this.renderNode)};
}
}
diff --git a/packages/flow-designer/src/components/port/PortsRenderer.component.tsx b/packages/flow-designer/src/components/port/PortsRenderer.component.tsx
index 9861a8aafda..8cad7537601 100644
--- a/packages/flow-designer/src/components/port/PortsRenderer.component.tsx
+++ b/packages/flow-designer/src/components/port/PortsRenderer.component.tsx
@@ -10,7 +10,7 @@ function PortsRenderer({ ports, portTypeMap }: { ports: PortRecordMap; portTypeM
return ;
};
- return {ports.toArray().map(renderPort)};
+ return {ports.valueSeq().toArray().map(renderPort)};
}
export default PortsRenderer;
diff --git a/packages/flow-designer/src/constants/flowdesigner.model.ts b/packages/flow-designer/src/constants/flowdesigner.model.ts
index fda0409af81..ebba45c04fe 100644
--- a/packages/flow-designer/src/constants/flowdesigner.model.ts
+++ b/packages/flow-designer/src/constants/flowdesigner.model.ts
@@ -83,17 +83,22 @@ const nodeRecordDefinition = {
}),
};
+// Note: methods below use `this: any` to work around an Immutable.js v5 breaking change.
+// In v5, TypeScript infers `this` inside a Record({...}) shape as the plain object literal
+// (not the instantiated Record), so methods like getIn/get/set/setIn are not recognized.
+// `this: any` is a TypeScript-only fake parameter that suppresses the type check on `this`.
+// All affected methods are marked "TO BE REMOVED" — this is a transitional workaround only.
export class NodeRecord extends Record({
...nodeRecordDefinition,
- getPosition(): Position {
+ getPosition(this: any): Position {
return this.getIn(['graphicalAttributes', 'position']);
},
- getSize(): Size {
+ getSize(this: any): Size {
return this.getIn(['graphicalAttributes', 'nodeSize']);
},
- getNodeType(): string {
+ getNodeType(this: any): string {
return this.getIn(['graphicalAttributes', 'nodeType']);
},
}) {}
@@ -101,21 +106,21 @@ export class NodeRecord extends Record({
export class NestedNodeRecord extends Record({
...nodeRecordDefinition,
components: List(),
- getComponents(): Map {
+ getComponents(this: any): Map {
return this.get('components');
},
- setComponents(components: Map) {
+ setComponents(this: any, components: Map) {
return this.set('components', components);
},
- getPosition(): Position {
+ getPosition(this: any): Position {
return this.getIn(['graphicalAttributes', 'position']);
},
- getSize(): Size {
+ getSize(this: any): Size {
return this.getIn(['graphicalAttributes', 'nodeSize']);
},
- getNodeType(): string {
+ getNodeType(this: any): string {
return this.getIn(['graphicalAttributes', 'nodeType']);
},
}) {}
@@ -133,7 +138,7 @@ export const LinkRecord = Record({
}),
/** methods TO BE REMOVED */
- getLinkType(): string {
+ getLinkType(this: any): string {
return this.getIn(['graphicalAttributes', 'linkType']);
},
});
@@ -152,25 +157,25 @@ export const PortRecord = Record({
}),
/** methods TO BE REMOVED */
- getPosition(): Position {
+ getPosition(this: any): Position {
return this.getIn(['graphicalAttributes', 'position']);
},
- setPosition(position: Position): PortRecordType {
+ setPosition(this: any, position: Position): PortRecordType {
return this.setIn(['graphicalAttributes', 'position'], position);
},
- getPortType(): string {
+ getPortType(this: any): string {
return this.getIn(['graphicalAttributes', 'portType']);
},
- getPortDirection(): PortDirection {
+ getPortDirection(this: any): PortDirection {
return this.getIn(['graphicalAttributes', 'properties', 'type']);
},
- getPortFlowType(): string {
+ getPortFlowType(this: any): string {
return this.getIn(['data', 'flowType']);
},
- getIndex(): number {
+ getIndex(this: any): number {
return this.getIn(['graphicalAttributes', 'properties', 'index']);
},
- setIndex(index: number): PortRecordType {
+ setIndex(this: any, index: number): PortRecordType {
return this.setIn(['graphicalAttributes', 'properties', 'index'], index);
},
});
diff --git a/packages/flow-designer/src/constants/flowdesigner.proptypes.ts b/packages/flow-designer/src/constants/flowdesigner.proptypes.ts
index 83005e828a6..8fa1458fd91 100644
--- a/packages/flow-designer/src/constants/flowdesigner.proptypes.ts
+++ b/packages/flow-designer/src/constants/flowdesigner.proptypes.ts
@@ -1,25 +1,11 @@
import PropTypes from 'prop-types';
-import { recordOf } from 'react-immutable-proptypes';
-export const NodeType = recordOf({
- id: PropTypes.string.isRequired,
- position: recordOf({
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- }),
-});
+// Runtime shape validation (via recordOf) was removed as part of the
+// Immutable PropTypes migration. TypeScript types in
+// customTypings/index.d.ts provide compile-time type safety instead.
-export const PortType = recordOf({
- id: PropTypes.string.isRequired,
- nodeId: PropTypes.string.isRequired,
- position: recordOf({
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- }),
-});
+export const NodeType = PropTypes.object;
-export const LinkType = recordOf({
- id: PropTypes.string.isRequired,
- sourceId: PropTypes.string.isRequired,
- targetId: PropTypes.string.isRequired,
-});
+export const PortType = PropTypes.object;
+
+export const LinkType = PropTypes.object;
diff --git a/packages/flow-designer/src/customTypings/index.d.ts b/packages/flow-designer/src/customTypings/index.d.ts
index 43f1957527d..1f9f41a328a 100644
--- a/packages/flow-designer/src/customTypings/index.d.ts
+++ b/packages/flow-designer/src/customTypings/index.d.ts
@@ -1,4 +1,4 @@
-import { Record, Map } from 'immutable';
+import { RecordOf, Map } from 'immutable';
import { PORT_SINK, PORT_SOURCE } from '../constants/flowdesigner.constants';
/** $BASIC */
@@ -78,42 +78,42 @@ export interface LinkData {
export interface Link {
id: Id;
- source: Id;
- target: Id;
+ sourceId: Id;
+ targetId: Id;
data: LinkData;
graphicalAttributes: LinkGraphicalAttributes;
}
/** $RECORDS */
-export type PositionRecord = Record & Position;
+export type PositionRecord = RecordOf;
-export type SizeRecord = Record & Size;
+export type SizeRecord = RecordOf;
-export type PortRecord = Record & {
+export type PortRecord = RecordOf & {
getPosition: () => Position;
getPortType: () => string;
getPortDirection: () => PortDirection;
getPortFlowType: () => string;
getIndex: () => number;
setIndex: (index: number) => PortRecord;
-} & Port;
+};
// TODO add record
-export type NodeRecord = Record & {
+export type NodeRecord = RecordOf & {
getPosition: () => Position;
getSize: () => Size;
getNodeType: () => string;
-} & Node;
+};
-export type NestedNodeRecord = Record & {
+export type NestedNodeRecord = RecordOf & {
getPosition: () => Position;
getSize: () => Size;
getNodeType: () => string;
-} & Node;
+};
-export type LinkRecord = Record & {
+export type LinkRecord = RecordOf & {
getLinkType: () => string;
-} & Link;
+};
/** $STATE */
@@ -138,7 +138,7 @@ export type State = {
children: Map>;
nodeTypes: Map>;
links: Map>;
-} & Map & { getIn: getStateNodes | getStatePorts | getStateLinks | getStateIn | getStateOut };
+} & Map & { getIn: GetStateNodes | GetStatePorts | GetStateLinks | GetStateIn | GetStateOut };
/** $ACTIONS */
export interface PortActionAdd {
diff --git a/packages/flow-designer/src/reducers/__snapshots__/link.reducer.test.ts.snap b/packages/flow-designer/src/reducers/__snapshots__/link.reducer.test.ts.snap
index 7fc45954769..845852b53bf 100644
--- a/packages/flow-designer/src/reducers/__snapshots__/link.reducer.test.ts.snap
+++ b/packages/flow-designer/src/reducers/__snapshots__/link.reducer.test.ts.snap
@@ -1538,7 +1538,9 @@ Immutable.Map {
"targetId": "id2",
"data": Immutable.Map {
"attr": "attr",
- "type": "test",
+ "properties": Immutable.Map {
+ "type": "test",
+ },
},
"graphicalAttributes": Immutable.Map {
"properties": Immutable.Map {
@@ -1792,8 +1794,8 @@ Immutable.Map {
"graphicalAttributes": Immutable.Map {
"properties": Immutable.Map {
"attr": "attr",
+ "selected": false,
},
- "selected": false,
},
"getLinkType": [Function],
},
diff --git a/packages/flow-designer/src/reducers/__snapshots__/port.reducer.test.ts.snap b/packages/flow-designer/src/reducers/__snapshots__/port.reducer.test.ts.snap
index c4be4977e59..da4d1de524a 100644
--- a/packages/flow-designer/src/reducers/__snapshots__/port.reducer.test.ts.snap
+++ b/packages/flow-designer/src/reducers/__snapshots__/port.reducer.test.ts.snap
@@ -18,7 +18,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -138,7 +138,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -301,10 +301,10 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
- "id2": Immutable.Record {
- "id": "id2",
- "nodeId": "test",
+ "ports": Immutable.Map {
+ "id3": Immutable.Record {
+ "id": "id3",
+ "nodeId": undefined,
"data": Immutable.Map {
"properties": Immutable.Map {},
"flowType": undefined,
@@ -314,6 +314,9 @@ Immutable.Map {
"x": 10,
"y": 10,
},
+ "properties": Immutable.Map {
+ "index": 0,
+ },
},
"getPosition": [Function],
"setPosition": [Function],
@@ -323,9 +326,9 @@ Immutable.Map {
"getIndex": [Function],
"setIndex": [Function],
},
- "id3": Immutable.Record {
- "id": "id3",
- "nodeId": undefined,
+ "id2": Immutable.Record {
+ "id": "id2",
+ "nodeId": "test",
"data": Immutable.Map {
"properties": Immutable.Map {},
"flowType": undefined,
@@ -335,9 +338,6 @@ Immutable.Map {
"x": 10,
"y": 10,
},
- "properties": Immutable.Map {
- "index": 0,
- },
},
"getPosition": [Function],
"setPosition": [Function],
@@ -368,7 +368,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -432,7 +432,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -517,7 +517,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -602,7 +602,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
@@ -687,7 +687,7 @@ Immutable.Map {
"nodes": Immutable.Map {
"nodeId": Immutable.Map {},
},
- "ports": Immutable.OrderedMap {
+ "ports": Immutable.Map {
"id1": Immutable.Record {
"id": "id1",
"nodeId": undefined,
diff --git a/packages/flow-designer/src/reducers/link.reducer.ts b/packages/flow-designer/src/reducers/link.reducer.ts
index f206990e8d4..c96671b4a0d 100644
--- a/packages/flow-designer/src/reducers/link.reducer.ts
+++ b/packages/flow-designer/src/reducers/link.reducer.ts
@@ -48,13 +48,9 @@ export default function linkReducer(state = defaultState, action: any) {
'properties',
fromJS(action.data && action.data.properties) || Map(),
),
- graphicalAttributes: new LinkGraphicalAttributes(
- action.graphicalAttributes,
- ).set(
+ graphicalAttributes: new LinkGraphicalAttributes(action.graphicalAttributes).set(
'properties',
- fromJS(
- action.graphicalAttributes && action.graphicalAttributes.properties,
- ) || Map(),
+ fromJS(action.graphicalAttributes && action.graphicalAttributes.properties) || Map(),
),
}),
) // parcourir l'ensemble des parents et set le composant cible en tant que sucessors '
@@ -75,21 +71,11 @@ export default function linkReducer(state = defaultState, action: any) {
state.getIn(['ports', action.sourceId]).nodeId,
)
.setIn(
- [
- 'out',
- state.getIn(['ports', action.sourceId]).nodeId,
- action.sourceId,
- action.linkId,
- ],
+ ['out', state.getIn(['ports', action.sourceId]).nodeId, action.sourceId, action.linkId],
action.linkId,
)
.setIn(
- [
- 'in',
- state.getIn(['ports', action.targetId]).nodeId,
- action.targetId,
- action.linkId,
- ],
+ ['in', state.getIn(['ports', action.targetId]).nodeId, action.targetId, action.linkId],
action.linkId,
);
case FLOWDESIGNER_LINK_SET_TARGET:
@@ -116,12 +102,7 @@ export default function linkReducer(state = defaultState, action: any) {
action.linkId,
])
.setIn(
- [
- 'in',
- state.getIn(['ports', action.targetId]).nodeId,
- action.targetId,
- action.linkId,
- ],
+ ['in', state.getIn(['ports', action.targetId]).nodeId, action.targetId, action.linkId],
action.linkId,
)
.deleteIn([
@@ -132,8 +113,7 @@ export default function linkReducer(state = defaultState, action: any) {
.setIn(
[
'childrens',
- state.getIn(['ports', state.getIn(['links', action.linkId]).sourceId])
- .nodeId,
+ state.getIn(['ports', state.getIn(['links', action.linkId]).sourceId]).nodeId,
state.getIn(['ports', action.targetId]).nodeId,
],
state.getIn(['ports', action.targetId]).nodeId,
@@ -162,12 +142,7 @@ export default function linkReducer(state = defaultState, action: any) {
action.linkId,
])
.setIn(
- [
- 'out',
- state.getIn(['ports', action.sourceId]).nodeId,
- action.sourceId,
- action.linkId,
- ],
+ ['out', state.getIn(['ports', action.sourceId]).nodeId, action.sourceId, action.linkId],
action.linkId,
)
.deleteIn([
@@ -178,8 +153,7 @@ export default function linkReducer(state = defaultState, action: any) {
.setIn(
[
'parents',
- state.getIn(['ports', state.getIn(['links', action.linkId]).targetId])
- .nodeId,
+ state.getIn(['ports', state.getIn(['links', action.linkId]).targetId]).nodeId,
state.getIn(['ports', action.sourceId]).nodeId,
],
state.getIn(['ports', action.sourceId]).nodeId,
@@ -218,18 +192,10 @@ export default function linkReducer(state = defaultState, action: any) {
invariant(false, `Can't set an attribute on non existing link ${action.linkId}`);
}
- try {
- return state.mergeIn(
- ['links', action.linkId, 'graphicalAttributes'],
- fromJS(action.graphicalAttributes),
- );
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['links', action.linkId, 'graphicalAttributes', 'properties'],
- fromJS(action.graphicalAttributes),
- );
- }
+ return state.mergeIn(
+ ['links', action.linkId, 'graphicalAttributes', 'properties'],
+ fromJS(action.graphicalAttributes),
+ );
case FLOWDESIGNER_LINK_REMOVE_GRAPHICAL_ATTRIBUTES:
if (!state.getIn(['links', action.linkId])) {
@@ -249,15 +215,7 @@ export default function linkReducer(state = defaultState, action: any) {
invariant(false, `Can't set an attribute on non existing link ${action.linkId}`);
}
- try {
- return state.mergeIn(['links', action.linkId, 'data'], fromJS(action.data));
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['links', action.linkId, 'data', 'properties'],
- fromJS(action.data),
- );
- }
+ return state.mergeIn(['links', action.linkId, 'data', 'properties'], fromJS(action.data));
case FLOWDESIGNER_LINK_REMOVE_DATA:
if (!state.getIn(['links', action.linkId])) {
diff --git a/packages/flow-designer/src/reducers/node.reducer.ts b/packages/flow-designer/src/reducers/node.reducer.ts
index 3bf8c708ec2..d26c1947f51 100644
--- a/packages/flow-designer/src/reducers/node.reducer.ts
+++ b/packages/flow-designer/src/reducers/node.reducer.ts
@@ -1,4 +1,4 @@
-import Immutable, { Map, fromJS } from 'immutable';
+import { Map, fromJS } from 'immutable';
import invariant from 'invariant';
import { removePort } from '../actions/port.actions';
import portReducer from './port.reducer';
@@ -33,10 +33,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
switch (action.type) {
case FLOWDESIGNER_NODE_ADD:
if (state.getIn(['nodes', action.nodeId])) {
- invariant(
- false,
- `Can not create node ${action.nodeId} since it does already exist`,
- );
+ invariant(false, `Can not create node ${action.nodeId} since it does already exist`);
}
return state
@@ -45,22 +42,14 @@ const nodeReducer = (state: State = defaultState, action: any) => {
new NodeRecord({
id: action.nodeId,
type: action.nodeType,
- data: Immutable.Map(action.data).set(
+ data: Map(action.data).set(
'properties',
fromJS(action.data && action.data.properties) || Map(),
),
- graphicalAttributes: new NodeGraphicalAttributes(
- fromJS(action.graphicalAttributes),
- )
+ graphicalAttributes: new NodeGraphicalAttributes(fromJS(action.graphicalAttributes))
.set('nodeSize', new SizeRecord(action.graphicalAttributes.nodeSize))
- .set(
- 'position',
- new PositionRecord(action.graphicalAttributes.position),
- )
- .set(
- 'properties',
- fromJS(action.graphicalAttributes.properties) || Map(),
- ),
+ .set('position', new PositionRecord(action.graphicalAttributes.position))
+ .set('properties', fromJS(action.graphicalAttributes.properties) || Map()),
}),
)
.setIn(['out', action.nodeId], Map())
@@ -80,7 +69,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
.setIn(['childrens', Node.getId(action.node)], Map())
.setIn(['parents', Node.getId(action.node)], Map());
case FLOWDESIGNER_NODE_MOVE_START:
- if (!state.getIn('nodes', action.nodeId)) {
+ if (!state.getIn(['nodes', action.nodeId])) {
invariant(false, `Can't move node ${action.nodeId} since it doesn't exist`);
}
@@ -89,7 +78,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
new PositionRecord(action.nodePosition),
);
case FLOWDESIGNER_NODE_MOVE:
- if (!state.getIn('nodes', action.nodeId)) {
+ if (!state.getIn(['nodes', action.nodeId])) {
invariant(false, `Can't move node ${action.nodeId} since it doesn't exist`);
}
@@ -98,7 +87,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
new PositionRecord(action.nodePosition),
);
case FLOWDESIGNER_NODE_MOVE_END:
- if (!state.getIn('nodes', action.nodeId)) {
+ if (!state.getIn(['nodes', action.nodeId])) {
invariant(false, `Can't move node ${action.nodeId} since it doesn't exist`);
}
@@ -107,13 +96,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
['nodes', action.nodeId, 'graphicalAttributes', 'position'],
new PositionRecord(action.nodePosition),
)
- .deleteIn([
- 'nodes',
- action.nodeId,
- 'graphicalAttributes',
- 'properties',
- 'startPosition',
- ]);
+ .deleteIn(['nodes', action.nodeId, 'graphicalAttributes', 'properties', 'startPosition']);
case FLOWDESIGNER_NODE_APPLY_MOVEMENT:
return state.update('nodes', (nodes: NodeRecordMap) =>
nodes.map(node => {
@@ -142,33 +125,19 @@ const nodeReducer = (state: State = defaultState, action: any) => {
);
case FLOWDESIGNER_NODE_SET_TYPE:
if (!state.getIn(['nodes', action.nodeId])) {
- invariant(
- false,
- `Can't set node.type on node ${action.nodeid} since it doesn't exist`,
- );
+ invariant(false, `Can't set node.type on node ${action.nodeid} since it doesn't exist`);
}
return state.setIn(['nodes', action.nodeId, 'type'], action.nodeType);
case FLOWDESIGNER_NODE_SET_GRAPHICAL_ATTRIBUTES:
if (!state.getIn(['nodes', action.nodeId])) {
- invariant(
- false,
- `Can't set a graphical attribute on non existing node ${action.nodeId}`,
- );
+ invariant(false, `Can't set a graphical attribute on non existing node ${action.nodeId}`);
}
- try {
- return state.mergeIn(
- ['nodes', action.nodeId, 'graphicalAttributes'],
- fromJS(action.graphicalAttributes),
- );
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['nodes', action.nodeId, 'graphicalAttributes', 'properties'],
- fromJS(action.graphicalAttributes),
- );
- }
+ return state.mergeIn(
+ ['nodes', action.nodeId, 'graphicalAttributes', 'properties'],
+ fromJS(action.graphicalAttributes),
+ );
case FLOWDESIGNER_NODE_REMOVE_GRAPHICAL_ATTRIBUTES:
if (!state.getIn(['nodes', action.nodeId])) {
@@ -190,15 +159,7 @@ const nodeReducer = (state: State = defaultState, action: any) => {
invariant(false, `Can't set a data on non existing node ${action.nodeId}`);
}
- try {
- return state.mergeIn(['nodes', action.nodeId, 'data'], fromJS(action.data));
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['nodes', action.nodeId, 'data', 'properties'],
- fromJS(action.data),
- );
- }
+ return state.mergeIn(['nodes', action.nodeId, 'data'], fromJS(action.data));
case FLOWDESIGNER_NODE_REMOVE_DATA:
if (!state.getIn(['nodes', action.nodeId])) {
diff --git a/packages/flow-designer/src/reducers/port.reducer.test.ts b/packages/flow-designer/src/reducers/port.reducer.test.ts
index b87af0d362f..b9dd587504a 100644
--- a/packages/flow-designer/src/reducers/port.reducer.test.ts
+++ b/packages/flow-designer/src/reducers/port.reducer.test.ts
@@ -1,4 +1,4 @@
-import { Map, OrderedMap } from 'immutable';
+import { Map } from 'immutable';
import { defaultState } from './flow.reducer';
import portReducer from './port.reducer';
@@ -10,7 +10,7 @@ describe('Check port reducer', () => {
.set(
'ports',
// eslint-disable-next-line new-cap
- OrderedMap()
+ Map()
.set(
'id1',
new PortRecord({
diff --git a/packages/flow-designer/src/reducers/port.reducer.ts b/packages/flow-designer/src/reducers/port.reducer.ts
index 63a7da00fb6..1ce76b00e39 100644
--- a/packages/flow-designer/src/reducers/port.reducer.ts
+++ b/packages/flow-designer/src/reducers/port.reducer.ts
@@ -78,17 +78,13 @@ function indexPortMap(ports: PortRecordMap): PortRecordMap {
*/
function setPort(state: State, port: PortRecordType) {
const index: number =
- port.graphicalAttributes.properties.index ||
- calculateNewPortIndex(state.get('ports'), port);
+ port.graphicalAttributes.properties.index || calculateNewPortIndex(state.get('ports'), port);
const newState = state.setIn(
['ports', port.id],
new PortRecord({
id: port.id,
nodeId: port.nodeId,
- data: Map(port.data).set(
- 'properties',
- fromJS(port.data && port.data.properties) || Map(),
- ),
+ data: Map(port.data).set('properties', fromJS(port.data && port.data.properties) || Map()),
graphicalAttributes: Map(port.graphicalAttributes)
.set('position', new PositionRecord(port.graphicalAttributes.position))
.set(
@@ -121,10 +117,7 @@ export default function portReducer(state: State, action: PortAction): State {
switch (action.type) {
case FLOWDESIGNER_PORT_ADD:
if (!state.getIn(['nodes', action.nodeId])) {
- invariant(
- false,
- `Can't set a new port ${action.id} on non existing node ${action.nodeId}`,
- );
+ invariant(false, `Can't set a new port ${action.id} on non existing node ${action.nodeId}`);
}
return setPort(state, {
@@ -151,24 +144,13 @@ export default function portReducer(state: State, action: PortAction): State {
}
case FLOWDESIGNER_PORT_SET_GRAPHICAL_ATTRIBUTES:
if (!state.getIn(['ports', action.portId])) {
- invariant(
- false,
- `Can't set an graphical attribute on non existing port ${action.portId}`,
- );
+ invariant(false, `Can't set an graphical attribute on non existing port ${action.portId}`);
}
- try {
- return state.mergeIn(
- ['ports', action.portId, 'graphicalAttributes'],
- fromJS(action.graphicalAttributes),
- );
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['ports', action.portId, 'graphicalAttributes', 'properties'],
- fromJS(action.graphicalAttributes),
- );
- }
+ return state.mergeIn(
+ ['ports', action.portId, 'graphicalAttributes'],
+ fromJS(action.graphicalAttributes),
+ );
case FLOWDESIGNER_PORT_REMOVE_GRAPHICAL_ATTRIBUTES:
if (!state.getIn(['ports', action.portId])) {
@@ -190,15 +172,7 @@ export default function portReducer(state: State, action: PortAction): State {
invariant(false, `Can't set a data on non existing port ${action.portId}`);
}
- try {
- return state.mergeIn(['ports', action.portId, 'data'], fromJS(action.data));
- } catch (error) {
- console.error(error);
- return state.mergeIn(
- ['ports', action.portId, 'data', 'properties'],
- fromJS(action.data),
- );
- }
+ return state.mergeIn(['ports', action.portId, 'data'], fromJS(action.data));
case FLOWDESIGNER_PORT_REMOVE_DATA:
if (!state.getIn(['ports', action.portId])) {
@@ -223,16 +197,8 @@ export default function portReducer(state: State, action: PortAction): State {
),
)
.deleteIn(['ports', action.portId])
- .deleteIn([
- 'out',
- state.getIn(['ports', action.portId, 'nodeId']),
- action.portId,
- ])
- .deleteIn([
- 'in',
- state.getIn(['ports', action.portId, 'nodeId']),
- action.portId,
- ]);
+ .deleteIn(['out', state.getIn(['ports', action.portId, 'nodeId']), action.portId])
+ .deleteIn(['in', state.getIn(['ports', action.portId, 'nodeId']), action.portId]);
return newState.mergeDeep({
ports: indexPortMap(
filterPortsByDirection(
diff --git a/packages/flow-designer/src/selectors/nodeSelectors.test.ts b/packages/flow-designer/src/selectors/nodeSelectors.test.ts
index 5afa3b1bc85..3c3493200bf 100644
--- a/packages/flow-designer/src/selectors/nodeSelectors.test.ts
+++ b/packages/flow-designer/src/selectors/nodeSelectors.test.ts
@@ -1,4 +1,4 @@
-import { List, Map, OrderedMap } from 'immutable';
+import { List, Map } from 'immutable';
import * as Selectors from './nodeSelectors';
import {
NodeRecord,
@@ -189,7 +189,7 @@ describe('Testing node selectors', () => {
.set('id7', node7)
.set('id8', node8),
// eslint-disable-next-line new-cap
- ports: OrderedMap()
+ ports: Map()
.set('id1', port1)
.set('id2', port2)
.set('id3', port3)
@@ -277,7 +277,7 @@ describe('Testing node selectors on nested nodes', () => {
const givenState: State = Map({
nodes: Map().set('nodeIdA', nodeA).set('nodeIdB', nodeB),
// eslint-disable-next-line new-cap
- ports: OrderedMap(),
+ ports: Map(),
links: Map(),
parents: Map>(),
childrens: Map>(),
diff --git a/packages/flow-designer/tsconfig.json b/packages/flow-designer/tsconfig.json
index 8eaf460e3d3..0988b9076c3 100644
--- a/packages/flow-designer/tsconfig.json
+++ b/packages/flow-designer/tsconfig.json
@@ -6,6 +6,7 @@
"declaration": true,
"allowJs": false,
"incremental": true,
- "module": "CommonJs"
+ "module": "CommonJs",
+ "moduleResolution": "node"
}
}
diff --git a/packages/sagas/package.json b/packages/sagas/package.json
index 42408f28b7b..e39ead26059 100644
--- a/packages/sagas/package.json
+++ b/packages/sagas/package.json
@@ -41,7 +41,7 @@
},
"dependencies": {
"@talend/react-cmf": "^12.1.0",
- "immutable": "^3.8.2",
+ "immutable": "^5.1.5",
"redux-saga": "^1.4.2"
},
"peerDependencies": {
diff --git a/packages/stepper/package.json b/packages/stepper/package.json
index 63a665a3948..4a2ee323e96 100644
--- a/packages/stepper/package.json
+++ b/packages/stepper/package.json
@@ -64,7 +64,6 @@
"@testing-library/react-hooks": "^8.0.1",
"eslint": "^9.39.3",
"i18next": "^23.16.8",
- "immutable": "^3.8.2",
"jsdom": "^26.1.0",
"prettier": "^3.8.1",
"prop-types": "^15.8.1",
diff --git a/tools/scripts-config-cdn/umds.json b/tools/scripts-config-cdn/umds.json
index e51522b25fd..457f91e2ce6 100644
--- a/tools/scripts-config-cdn/umds.json
+++ b/tools/scripts-config-cdn/umds.json
@@ -80,15 +80,6 @@
}
}
},
- "react-immutable-proptypes": {
- "var": "ReactImmutableProptypes",
- "versions": {
- ">= 2.2.0": {
- "development": "/talend-umds/ReactImmutableProptypes.min.js",
- "production": "/talend-umds/ReactImmutableProptypes.min.js"
- }
- }
- },
"react-popper": {
"var": "ReactPopper",
"versions": {
diff --git a/yarn.lock b/yarn.lock
index 51fed4ccd7e..32e2ef93353 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9476,15 +9476,10 @@ ignore@^7.0.5:
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381"
integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
-immutable@^3.8.2:
- version "3.8.2"
- resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
- integrity sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==
-
-immutable@^5.0.2:
- version "5.1.4"
- resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.4.tgz#e3f8c1fe7b567d56cf26698f31918c241dae8c1f"
- integrity sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==
+immutable@^5.0.2, immutable@^5.1.5:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.5.tgz#93ee4db5c2a9ab42a4a783069f3c5d8847d40165"
+ integrity sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==
import-fresh@^3.2.1, import-fresh@^3.3.0:
version "3.3.1"
@@ -9608,7 +9603,7 @@ interpret@^3.1.1:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
-invariant@^2.2.2, invariant@^2.2.4:
+invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -13732,13 +13727,6 @@ react-i18next@^13.5.0:
"@babel/runtime" "^7.22.5"
html-parse-stringify "^3.0.1"
-react-immutable-proptypes@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz#cce96d68cc3c18e89617cbf3092d08e35126af4a"
- integrity sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==
- dependencies:
- invariant "^2.2.2"
-
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0, react-is@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"