BREAKING CHANGE until 2.0.0 - Talend/ui GitHub Wiki

v2.0.0

We planned to merge the following PR with breaking changes:

how to pre release:

  • update all corresponding PRs with master

  • create a tmp/ui-2-pre-release branch from master

  • merge the following branch in it

  • jmfrancois/chore/tui-271-router

  • jmfrancois/feat/cmf/omit-props-default-true

  • jmfrancois/feat/tui-298-heading-font-size

then at the root:

  • yarn
  • npm run publish (select major pre release)

v0.210.0

Before After Explanation
props.onMouseOver - Not accessible. This would introduce performance issues with keyboad navigation. But this is not used, so let's remove it.
props.onSelect(event, jsonpath) props.onSelect(event, { jsonpath }) This simplifies the code. This is triggered through TreeGesture HOC that takes an item and pass it through to the props callback. This is simple and compatible with TreeView and the new ObjectViewer apis.
- Required props.onToggleAllSiblings(event, siblings) This is for accessibility. It is triggered on * keydown to expand all the nodes at the same level
has been removed.

Before

import ObjectViewer from '@talend/react-components/lib/ObjectViewer';

class MyComponent extends React.Component {
	...

	mouseOverHandler(event, item) {}

	selectHandler(event, jsonpath) {}

	render() {
		return (
			<ObjectViewer
				onMouseOver={this.mouseOverHandler}
				onSelect=(this.selectHandler}
				...
			/>
		);
	}
}

After

import ObjectViewer from '@talend/react-components/lib/ObjectViewer';

class MyComponent extends React.Component {
	...

	selectHandler(event, jsonpath) {}

	toggleAllHandler(event, itemsToToggle) {}

	render() {
		return (
			<ObjectViewer
				onSelect=(this.selectHandler}
				onToggleAllSiblings={this.toggleAllHandler}
				...
			/>
		);
	}
}

v0.212.0

Before (backend response)

[
	{
		"name": "Management Console",
		"uri": "https://www.talend.com/products#tmc",
		"icon": "tmc"
	},
	...
]

After

[
	{
		"id": "TMC",
		"name": "Management Console",
		"url": "https://www.talend.com/products#tmc",
		"icon": "tmc"
	},
	...
]

v0.209.0

{
	values: [undefined],
	path: 'undefined',
}

After:

{
	'==': [{ var: 'undefined' }, undefined],
}

Before After Explanation
props.onClick props.onToggle This api was awful, ask anyone when is it triggered (select/toggle ?)
props.structure[].selected props.selectedId
props.structure[].toggled props.structure[].isOpened Toggle means the switch of a 2-state element. Toggled is not explicit at all (opened/closed/depending-on-initial-state ?)
onToggle/onSelect (item) onToggle/onSelect (event, item) This is to align the apis so we can wrap them with the same HOC as ObjectViewer for gesture
- Required props.onToggleAllSiblings(event, siblings) This is for accessibility. It is triggered on * keydown to expand all the nodes at the same level

Before

import TreeView from '@talend/react-components/lib/TreeView'

class MyComponent extends React.Component {
	...

	toggleHandler(item) {}

	selectHandler(item) {}

	render() {
		const structure = [{ id: 'first', name: 'awesome folder', selected: true, toggled: true }];
		return (
			<TreeView
				structure={structure}
				onClick={this.toggleHandler}
				onSelect={this.selectHandler}
				...
			/>
		);
	}
}

After

import TreeView from '@talend/react-components/lib/TreeView'

class MyComponent extends React.Component {
	...

	toggleHandler(event, item) {}

	toggleAllHandler(event, itemsToToggle) {}

	selectHandler(event, item) {}

	render() {
		const structure = [{ id: 'first', name: 'awesome folder', isOpened: true }];
		return (
			<TreeView
				structure={structure}
				selectedId={'first'}
				onToggle={this.toggleHandler}
				onToggleAllSiblings={this.toggleAllHandler}
				onSelect={this.selectHandler}
				...
			/>
		);
	}
}

Change 1:

The component was only a bar, with buttons, but not anymore. It takes a props.children to properly place it in the selected tab panel.
Before

<TabBar items={items} selectedKey={selectedKey} ... />
{items.map(({ item, index }) => {
	if (selectedKey !== item.key) {
		return null;
	}
	return (
		<div key={index} aria-describedby={item.id}>
			My Tab {item.label} content
		</div>
	);
})}

After

const selectedItem = items.find(item => selectedKey === item.key);

<TabBar items={items} selectedKey={selectedKey} ... >
	My Tab {selectedItem.label} content
</TabBar

Change 2:

TabBar doesn't pass items id anymore. They are generated based on the id passed to TabBar.
Before

const items = [
	{ id: 'my-custom-tab-1', key: '1', label: 'Tab 1' },
	{ id: 'my-custom-tab-2', key: '2', label: 'Tab 2' },
	{ id: 'my-custom-tab-3', key: '3', label: 'Tab 3' },	
];

<TabBar items={items} ... />

After

const items = [
	{ key: '1', label: 'Tab 1' },
	{ key: '2', label: 'Tab 2' },
	{ key: '3', label: 'Tab 3' },	
];

<TabBar id="my-custom" items={items} ... />

Note:

If you still want to manage the panels outside, you can still generate the tab ids to match your panels aria-describedby.

function generateChildId(key, kind) {
	if (kind === 'tab') {
		return `my-custom-id-${key}`;
	}
	return null;
}

<TabBar items={items} generateChildId={generateChildId} ... />

v0.206.0

conditions uiSchema entry is now an object supporting recursivity.

v0.205.0

Extra props provided to the component are now spread on the svg element, not the span container.

Example:

import PieChart from '@talend/react-components/lib/PieChart';

<PieChart aria-label='My text alternative' />

Before

<span arial-label='My text alternative'>
    <svg></svg>
    <span></span>
</span>

After

<span>
    <svg arial-label='My text alternative'></svg>
    <span></span>
</span>

0.204.0

editMode flag is no longer managed by the SubHeaderBar container, but by the new EditableText container. The getEditMode selector has been removed.

0.199.0

Remove it from CMF.

Before

function MyComponent(props) {
  return <ul>{props.getCollection('foo').map((item, key) => <li key={key}>item.get('label')</li>}</ul>
}
export default cmfConnect({})(MyComponent);

After

function MyComponent(props) {
  return <ul>{props.foo.map((item, key) => <li key={key}>item.get('label')</li>}</ul>
}
function mapStateToProps(state) {
  return { foo: state.cmf.collections.get('foo') };
}
export default cmfConnect({ mapStateToProps })(MyComponent);

0.197.0

Props Status Alternative
itemSelectCallback Removed onSelect
itemToggleCallback Removed onClick

0.193.0

0.188.0

Before :

{
    "dependencies": {
        "react-addons-css-transition-group": "15.6.2"
    }
}

After :

{
    "dependencies": {
        "react-transition-group": "^2.3.1"
    }
}

0.187.0

Before:

import { api } from '@talend-react-cmf';

After:

import api from '@talend-react-cmf';

A codemode has been provided by the PR:

cd ui/scripts/cmf
yarn
jscodeshift -t api_to_index.js ../../../YOUR_SRC_FOLDER

0.186.0

Before

{
    "jsonSchema": {
        "title": "Form with live validation",
        "type": "object",
        "properties": {
            "name": {
                "title": "Name",
                "type": "string",
                "minLength": 3,
                "required": true
            },
            "email": {
                "title": "Email",
                "type": "string",
                "pattern": "^\\S+@\\S+$",
                "minLength": 5,
                "required": true
            }
        }
    }
}

After

{
    "jsonSchema": {
        "title": "Form with live validation",
        "type": "object",
        "required": ["name", "email"],
        "properties": {
            "name": {
                "title": "Name",
                "type": "string",
                "minLength": 3
            },
            "email": {
                "title": "Email",
                "type": "string",
                "pattern": "^\\S+@\\S+$",
                "minLength": 5
            }
        }
    }
}

0.180.0

Adapt the component Form.js to call onChange and onSubmit with the same number of parameter as UIForm component. First is the event or null (we don't have the event with RJSF).

Function Before After
onChange props.onChange(...args) props.onChange(null, ...args)
onSubmit props.onSubmit(changes) props.onSubmit(null, changes)
Icon Changes
logo-dp Removed. Use `tdp-(colored
logo-ic Removed. Use `tic-(colored
logo-mc Removed. Use `tmc-(colored

0.172.0

on settings, the actionCreator's props or payload is not supported anymore.

Before After
actionCreator:'myactionCreator' onClickActionCreator:'myactionCreator'

0.168.0

Before After
props.bsDialogProps all props are just spread to the Modal component

Before

	const bsDialogProps = {
		dialogClassName: 'tmc-conductor-dialog',
		keyboard: true,
		onHide: dispatchProps.cancelItemsRemove,
	};
        return <Dialog bsDialogProps={bsDialogProps}/>

after

	const bsDialogProps = {
		dialogClassName: 'tmc-conductor-dialog',
		keyboard: true,
		onHide: dispatchProps.cancelItemsRemove,
	};
        return <Dialog {...bsDialogProps} />

v0.167.0

(#1172) adding additional headers from middleware configuration. Before the action headers replaced the default one (if passed), since that PR they are spreaded. One of the issue you might encountered is that the Content-Type attribute in the default header is not overriden anymore so your request which uses formData might not work anymore. Since the Content-Type needs to be left empty in order for the browser to fill all related headers, there's no workaround if you encountered this issue, (#1210) will fix that issue and remove the Content-Type in case there's a formData passed (just like in sagas/http.js).

v0.165.0

(#1156) have change the modal CSS to align it to guideline. If you have custom CSS or if you import some of the file directly it can be broken: @talend/react-components/src/ConfirmDialog/ConfirmDialog.scss has been deleted

v0.164.0

App switcher is now in Brand section. If you have an app switcher (props.product), avoid passing props.brand.onClick. In that case you'll have the onClick execution everytime you open the app switcher.

v0.162.0

You may have issue in your tests with bootstrap component. Before:

import { NavItem } from '@talend/react-components';
import { NavItem as BootstrapNavItem } from '@talend/react-components';
NavItem === BootstrapNavItem; // true

After

import { NavItem } from '@talend/react-components';
import { NavItem as BootstrapNavItem } from '@talend/react-components';
import wrap from '@talend/react-components/lib/wrap'
;
NavItem === BootstrapNavItem; // false
NavItem === wrap(BootstrapNavItem, 'NavItem'); // true

v0.161.0

Before After
props.renderers props.getComponent
props.name no more resolve use actionId or componentId with "props" settings
props.available as string not supported anymore use props.availableExpression
props.active as string not supported anymore use props.activeExpression
props.disabled as string not supported anymore use props.disabledExpression
props.inProgress as string not supported anymore use props.inProgressExpression

v0.160.0

Before

AWS-kinesis.svg

After

aws-kinesis.svg

Before

<Typeahead onToggle={func} />         // button
<Typeahead onToggle={undefined} />    // input

After

<Typeahead onToggle={func} docked />  // button
<Typeahead onToggle={func} />         // input
  • docked === true && onToggle !== undefined : the toggle button is displayed
  • docked !== true || onToggle === undefined : the typeahead input is displayed
Before After
props.selected props.selectedKey
Before After
props.tabs.selected props.tabs.selectedKey
Before After
props.tabs.selected props.tabs.selectedKey

v0.157.0

Before

function onEnter(nextState, replace) { }
function onLeave(nextState, replace) { }

After

function onEnter(router, dispatch)
 { const { nextState, replace } = router; }
function onLeave(router, dispatch) { }

v0.156.0

name new location
getCollectionFromPath selectors.collections.find
findCollectionPathListItem selectors.collections.findListItem
name change
+ sagaParams object spread to get uri / resource type / redirectUrl / resourcePath & routerParamsAttribute
- uri moved in object param
- resourceType moved in object param
- resourcePath moved in object param

Check the component doc

v0.153.0

name change
props.components replaced by the new Inject API
props.left added with the same API has the ActionBar
props.center added with the same API has the ActionBar
props.right added with the same API has the ActionBar

Check the component doc Check the Inject component doc

v0.153.0

v0.152.0

Spread viewProps when calling mapStateToProps so more stuff can be handled. For example, currently cmf only handle expression on first level of props, with this change, we can do expression evaluation under props.list for List component.

v0.151.0

  • Container: Form
  • PR: https://github.com/Talend/ui/pull/1031
  • Changes: With Form container in default export, we must have form as dependency on the project that import containers. Remove Form from default export and import it à la lodash when you need it.

Before

import { Form } from '@talend/react-containers'

After

import Form from '@talend/react-containers/lib/Form'

0.150.0

  • Component: Typeahead
  • PR: chore: upgrade react-autowhatever
  • Changes : we upgraded React-autowhatever from 7.0.0 to 10.1.0. We ensured old props compatibility, but overriding some props have been changed.
Before After
props.theme.itemFocused props.theme.itemHighlighted
  • Component: Form's Datalist widget
  • PR: [chore(react): Updates to React 16(https://github.com/Talend/ui/pull/761)
  • Changes : we upgraded React-autowhatever from 7.0.0 to 10.1.0. Custom item container have api changes Now containerProps are in a nested object props.containerProps instead of directly in props.

Before

function renderItemsContainer({ children, ...containerProps }) {
    return (
        <div {...containerProps}>
            {children}
        </div>
    );
}

function CustomDatalist() {
    return (
		<DatalistWidget
			{...otherProps}
			renderItemsContainer={renderItemsContainer}
		/>
	);
}

After

function renderItemsContainer({ children, containerProps }) {
    return (
        <div {...containerProps}>
            {children}
        </div>
    );
}

v0.143.0

Old Props New props
selected status

v0.142.0

Display name of this component was HeaderBar now Container(HeaderBar) Change made for consistency, and also because HeaderBar is already in use inside the component repository.

v0.141.0

The parameter used to properly compute resource information and how to call the URL to delete resource have moved from view settings to a saga factory

see documentation added on how to use this peculiar container

V0.140.0

Before Containers was working on it's own. Now you need to register them in your configure.js (it's CMF)

import { registerAllContainers } from '@talend/react-containers/lib/register';

registerAllContainers();

v0.138.0

Some constant from CMF/middlewares/http/constants are renamed

Before After
HTTP_REQUEST ACTION_TYPE_HTTP_REQUEST
HTTP_RESPONSE ACTION_TYPE_HTTP_RESPONSE
HTTP_ERRORS ACTION_TYPE_HTTP_ERRORS

v0.137.0

Before After
import { Slider } from '@talend/react-component'; import Slider from '@talend/react-component/lib/Slider'

v0.130.0

Before After
generated id was undefined-add on the add button if no was given no id is generated for the the add button

v0.125.0

Before After
emptyLabel i18next t() fn will do the magic trick by providing LISTVIEW_EMPTY
noResultLabel i18next t() fn will do the magic trick by providing LISTVIEW_NO_RESULT
toggleAllLabel i18next t() fn will do the magic trick by providing LISTVIEW_ITEMS_TOGGLE_ALL
searchPlaceholder i18next t() fn will do the magic trick by providing LISTVIEW_HEADERINPUT_SEARCH_PLACEHOLDER

Before this, action ids were ignored. Now, if an id is provided per action, it will be used instead of the label ; so it could break some QA tests.

v0.121.0

Before After
expandTitle i18next t() fn will do the magic trick by providing SIDEPANEL_EXPAND
collapseTitle i18next t() fn will do the magic trick by providing SIDEPANEL_COLLAPSE

v0.120.0

  • PR 807 [enhancement(component/Headerbar): small change]

The brand of the header bar used name to be rendered as the application title.

Using containers and cmf, name is used to resolve CMFAction from the registry.

To be able to use name to describe the CMFAction associated to the Brand section of the header bar, label has to be used for application title rendering and name to resolve CMFAction

v0.97.0

  • PR #634 [feat(VirtualizedList): adapt and enhance component objects]

List component object has entirely changed.

package name

Before

<dependency>
    <groupId>com.talend</groupId>
    <artifactId>component-objects</artifactId>
    <version>1.0.0</version>
</dependency>
import com.talend.component.*;

After

<dependency>
    <groupId>org.talend</groupId>
    <artifactId>component-objects</artifactId>
    <version>0.97.0</version>
</dependency>
import org.talend.component.*;

Explanation : this aligns the package name with all talend projects, and align version to Talend/ui

WebDriver configuration

Before

this.driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

After

// removed this configuration

Explanation : when the component-objects were instantiated, it was overriding the timeout configuration of the WebDriver. This should not be here, and only managed by the test project.

list.getItems()

Before

list.getItems(); // this returns all buttons in the table title cells

After

List<WebElement> titles = list
    .getTable(optional_id)              // get the table display component object
    .getItems()                         // get all the items rows
    .stream()
    .map(Item::getTitle)                // get the title button of each items
    .collect(Collectors.toList());

// no simple way, must take all items, map them to all titles, map them to all actions...
List<WebElement> actions = list
    .getTable(optional_id)                                  // get the table display component object
    .getItems()                                             // get all the items rows
    .stream()
    .map(item -> item.getCell(columnKey).getActions())      // get the title cell
    .flatMap(List::stream)                                  // flatten
    .collect(Collectors.toList());

Explanation : getting all title buttons and actions is not a real use case. There are more api method to do more precise things.

list.getItemActionButton(String label, String listType, String action)

Before

final WebElement actionButton = list.getItemActionButton(label, listType, action);

// move mouse to button to trigger mouseover and click
final Actions action = new Actions(driver);
action.moveToElement(actionButton).click().build().perform();

After

final Item item = list
    .getTable(optional_id)      // get the table display component object
    .getItem(titleLabel);       // get item row that fit the provided title label

// if you need to get the title button
final WebElement titleButton = item.getTitle();

// if you need to click on title button
item.clickOnTitle();

// if you need to get an item action
final WebElement actionButton = item.getAction(part_of_id_to_match); // the id was "listType:action" before

// if you need to click on an action
item.clickOnAction(part_of_id_to_match); // the id was "listType:action" before

Explanation :

  • the buttons should have ids or part of ids that are similar
  • listType and action parameters are specific to a project. They are used to create the id.

list.hasItem(String name)

Before

final boolean exists = list.hasItem(titleLabel);

After

final boolean exists = list.getTable().hasItem(titleLabel);

v0.96.0

  • PR #629 [feat(theme): update colors]

4 colors are gone :

  • $limeade : replace by $rio-grande
  • $pirate-gold : not used
  • $mine-shaft : replace by $dove-gray
  • $smalt-blue : not used

v0.71.0

  • PR #364 [feat: onTrigger !== onChange]

Form on change was binded not on underlying onChange api but, on trigger api.

Old on change behavior was migrated to onTrigger property. On change underlying behavior is now bound to onChange

Before

<Form
	data={schema}
	onChange={this.onChange}
	onSubmit={this.onSubmit}
	actions={this.formActions(this.props.definition, this.props.formData.label, onCancelAction)}
	buttonBlockClass={buttonBlockClass}
/>

After

<Form
	data={schema}
	onTrigger={this.onTrigger}
	onSubmit={this.onSubmit}
	actions={this.formActions(this.props.definition, this.props.formData.label, onCancelAction)}
	buttonBlockClass={buttonBlockClass}
/>

Can even use real onChange

<Form
	data={schema}
	onChange={this.onChange}
	onTrigger={this.onTrigger}
	onSubmit={this.onSubmit}
	actions={this.formActions(this.props.definition, this.props.formData.label, onCancelAction)}
	buttonBlockClass={buttonBlockClass}
/>

v0.66.0

The mutateCollection operations Old format New format
delete Array of index Array of item id
update Map of key/value = index/item Map of key/value = id/item

next release

v0.61.0

  • Component: List
  • PR: feat(List): filter dock mode
  • Changes : props.toolbar.onFilter was taking (value, event) args, it's now aligned with other components (event, value)
  • Action structure must be in payload
  • PR 135
  • Changes:
                actions['menu:first'] = {
                        label: 'First',
                        icon: 'talend-streams',
-                       type: 'MENU_TEST',
+                       payload: {
+                               type: 'MENU_',
+                       },
                };
⚠️ **GitHub.com Fallback** ⚠️