Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/remove-immutable-cmf-cqrs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@talend/react-cmf-cqrs': major
---

feat: remove immutable dependency

## Breaking changes

`state.ack` is now a plain object. Consumers reading ack state directly must migrate `.get(key)` → `[key]`.
17 changes: 17 additions & 0 deletions .changeset/remove-immutable-cmf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@talend/react-cmf': major
---

feat: remove immutable dependency

## Breaking changes

The CMF Redux store no longer uses ImmutableJS. `state.cmf.collections` and `state.cmf.components` are now plain objects.

Migrate:
- `.get(key)` → `[key]`
- `.getIn([a, b])` → `lodash.get(state, [a, b])`
- `.toJS()` → identity (already plain JS)
- `.size` → `Object.keys(x).length`

The `cmf.selectors.collections.*` and `cmf.selectors.components.*` APIs still work and are the recommended way to access CMF state.
11 changes: 11 additions & 0 deletions .changeset/remove-immutable-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@talend/react-components': major
---

feat: remove immutable dependency

## Breaking changes

The `Iterable.isIterable` backward-compat guard was removed from `ActionDropdown`. Consumers passing an Immutable List as `items` will no longer work — migrate to plain arrays.

`immutable` and `react-immutable-proptypes` removed from published `dependencies`.
15 changes: 15 additions & 0 deletions .changeset/remove-immutable-containers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@talend/react-containers': major
---

feat: remove immutable dependency

## Breaking changes

`defaultState` is now a plain object. Selectors updated accordingly.

Migrate:
- `.get(key)` → `[key]`
- `.getIn([a, b])` → `lodash.get(state, [a, b])`
- `.toJS()` → identity (already plain JS)
- `.size` → `Object.keys(x).length`
9 changes: 9 additions & 0 deletions .changeset/remove-immutable-sagas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@talend/react-sagas': major
---

feat: remove immutable dependency

## Breaking changes

Exported functions `findPenders(state)` and `findPenderById(state, id)` now return plain JS values instead of Immutable structures. Any consumer calling `.get()`, `.set()`, `.toJS()`, or `.size` on the return values must migrate to plain object access.
5 changes: 5 additions & 0 deletions .changeset/remove-immutable-stepper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@talend/react-stepper': patch
---

feat: remove immutable dependency
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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-*
52 changes: 52 additions & 0 deletions docs/migration-guides/migration-guide-remove-immutable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Migration Guide: Removal of ImmutableJS

This is the index for per-package migration guides covering the breaking changes introduced by the removal of [ImmutableJS](https://immutable-js.com/) from the Talend UI monorepo.

## Affected packages

| Package | Version bump | Guide |
| -------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------- |
| `@talend/react-cmf` | **MAJOR** | [migration-guide-remove-immutable-cmf.md](./remove-immutable/migration-guide-remove-immutable-cmf.md) |
| `@talend/react-containers` | **MAJOR** | [migration-guide-remove-immutable-containers.md](./remove-immutable/migration-guide-remove-immutable-containers.md) |
| `@talend/react-cmf-cqrs` | **MAJOR** | [migration-guide-remove-immutable-cmf-cqrs.md](./remove-immutable/migration-guide-remove-immutable-cmf-cqrs.md) |
| `@talend/react-sagas` | **MAJOR** | [migration-guide-remove-immutable-sagas.md](./remove-immutable/migration-guide-remove-immutable-sagas.md) |
| `@talend/react-components` | **MAJOR** | [migration-guide-remove-immutable-components.md](./remove-immutable/migration-guide-remove-immutable-components.md) |
| `@talend/react-stepper` | patch | [migration-guide-remove-immutable-stepper.md](./remove-immutable/migration-guide-remove-immutable-stepper.md) |

---

## Quick reference: ImmutableJS → Plain JS

| ImmutableJS | Plain JS |
| ------------------------ | ---------------------------------------------------------- |
| `map.get(key)` | `obj[key]` |
| `map.getIn([a, b, c])` | `lodash.get(obj, [a, b, c])` |
| `map.set(key, val)` | `{ ...obj, [key]: val }` |
| `map.setIn([a, b], val)` | `produce(obj, d => set(d, [a, b], val))` (immer + lodash) |
| `map.merge(other)` | `{ ...obj, ...other }` |
| `map.delete(key)` | `const { [key]: _, ...rest } = obj; return rest;` |
| `map.has(key)` | `key in obj` |
| `list.push(item)` | `[...arr, item]` |
| `list.filter(fn)` | `arr.filter(fn)` |
| `list.filterNot(fn)` | `arr.filter(item => !fn(item))` |
| `list.find(fn)` | `arr.find(fn)` |
| `list.includes(val)` | `arr.includes(val)` |
| `Map.isMap(x)` | `typeof x === 'object' && x !== null && !Array.isArray(x)` |
| `List.isList(x)` | `Array.isArray(x)` |
| `Iterable.isIterable(x)` | N/A — remove the guard |
| `fromJS(obj)` | `obj` (already plain) |
| `x.toJS()` | `x` (already plain) |
| `x.size` | `Array.isArray(x) ? x.length : Object.keys(x).length` |

## Useful grep patterns

```bash
# Find all Immutable imports
grep -r "from 'immutable'" src/ --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx"

# Find react-immutable-proptypes usage
grep -r "react-immutable-proptypes" src/ --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx"

# Find residual Immutable method calls
grep -rE "\.(getIn|setIn|toJS|fromJS|isMap|isList|isIterable)\(" src/
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Migration Guide: `@talend/react-cmf-cqrs` — Removal of ImmutableJS

**Version bump**: MAJOR

---

## What changed

`state.ack` is now a plain JavaScript object. The Immutable methods previously used to read/write acknowledgment state have been replaced with standard object operations.

Removed dependency: `immutable`.

---

## Breaking changes

### 1. `state.ack` is now a plain object

The ACK reducer now stores state as `{ [requestId]: { data, actionCreator, received } }` — a plain JS object keyed by `requestId`.

**Before**

```js
// state.ack was an Immutable.Map
const ackEntry = state.ack.getIn([requestId, 'data']);
const received = state.ack.getIn([requestId, 'received']);
const actionCreator = state.ack.getIn([requestId, 'actionCreator']);

// checking if an entry exists
const exists = state.ack.has(requestId);
```

**After**

```js
// state.ack is now a plain object: { [requestId]: { data, actionCreator, received } }
const ackEntry = state.ack[requestId]?.data;
const received = state.ack[requestId]?.received;
const actionCreator = state.ack[requestId]?.actionCreator;

// checking if an entry exists
const exists = requestId in state.ack;
```

---

### 2. `ACKDispatcher` — `acks` prop is a plain object

The `ACKDispatcher` component now iterates over `props.acks` using `Object.entries()`. Previously it was iterated as an Immutable-style iterable.

If you use `ACKDispatcher` through `cmfConnect` (the standard usage), this is handled automatically — `state.ack` is now a plain object and is passed as `acks` directly. **No action required** for this pattern.

If you pass `acks` **manually as a prop**, it must be a plain object:

```js
// Before — custom acks prop (Immutable)
import { Map } from 'immutable';
<ACKDispatcher
acks={Map({
'req-123': Map({ received: true, actionCreator: 'dataset:fetchAll', data: {} }),
})}
/>

// After — custom acks prop (plain object)
<ACKDispatcher
acks={{
'req-123': { received: true, actionCreator: 'dataset:fetchAll', data: {} },
}}
/>
```

---

### 3. Test fixtures

Tests that build mock ACK state with Immutable must be updated:

```js
// Before
import Immutable from 'immutable';
const state = {
ack: Immutable.fromJS({
'req-123': { received: false, data: null, actionCreator: 'dataset:fetch' },
}),
};

// After
const state = {
ack: {
'req-123': { received: false, data: null, actionCreator: 'dataset:fetch' },
},
};
```

---

## Checklist

- [ ] Replace `state.ack.getIn([requestId, 'key'])` → `state.ack[requestId]?.key`
- [ ] Replace `state.ack.has(requestId)` → `requestId in state.ack`
- [ ] Ensure manually-passed `acks` props are plain objects
- [ ] Update test fixtures to use plain objects instead of `Immutable.fromJS({...})`
- [ ] Remove `immutable` from your own `package.json` if transitively relied on
Loading
Loading