UI: update Ember to 3.28.6 (#16616)

---------

Co-authored-by: wenincode <tyler.wendlandt@hashicorp.com>
This commit is contained in:
Valeriia Ruban 2023-03-20 15:41:47 -07:00 committed by GitHub
parent 7724363f19
commit 6e75bebd8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 2790 additions and 5498 deletions

View File

@ -43,7 +43,7 @@ references:
# When updating the Go version, remember to also update the versions in the # When updating the Go version, remember to also update the versions in the
# workflows section for go-test-lib jobs. # workflows section for go-test-lib jobs.
go: &GOLANG_IMAGE docker.mirror.hashicorp.services/cimg/go:1.20.1 go: &GOLANG_IMAGE docker.mirror.hashicorp.services/cimg/go:1.20.1
ember: &EMBER_IMAGE docker.mirror.hashicorp.services/circleci/node:14-browsers ember: &EMBER_IMAGE docker.mirror.hashicorp.services/circleci/node:16-browsers
ubuntu: &UBUNTU_CI_IMAGE ubuntu-2004:202201-02 ubuntu: &UBUNTU_CI_IMAGE ubuntu-2004:202201-02
cache: cache:
yarn: &YARN_CACHE_KEY consul-ui-v9-{{ checksum "ui/yarn.lock" }} yarn: &YARN_CACHE_KEY consul-ui-v9-{{ checksum "ui/yarn.lock" }}

View File

@ -1,4 +1,4 @@
FROM docker.mirror.hashicorp.services/circleci/node:14-browsers FROM docker.mirror.hashicorp.services/circleci/node:16-browsers
USER root USER root

View File

@ -1 +1 @@
14 16

View File

@ -25,7 +25,6 @@ deps: clean
cd packages/consul-ui && \ cd packages/consul-ui && \
$(MAKE) deps $(MAKE) deps
# Build a distribution of the UI for Vercel previews. # Build a distribution of the UI for Vercel previews.
# The distribution must be copied into the ui/ subfolder # The distribution must be copied into the ui/ subfolder
# in order to mirror the go binary # in order to mirror the go binary

View File

@ -24,6 +24,6 @@
"ember-basic-dropdown": "3.0.21" "ember-basic-dropdown": "3.0.21"
}, },
"engines": { "engines": {
"node": ">=10 <=14" "node": ">=14 <=16"
} }
} }

View File

@ -49,17 +49,17 @@ module.exports = {
// node files // node files
{ {
files: [ files: [
'.eslintrc.js', './tailwind.config.js',
'tailwind.config.js', './.docfy-config.js',
'.docfy-config.js', './.eslintrc.js',
'.prettierrc.js', './.prettierrc.js',
'.template-lintrc.js', './.template-lintrc.js',
'ember-cli-build.js', './ember-cli-build.js',
'testem.js', './testem.js',
'blueprints/*/index.js', './blueprints/*/index.js',
'config/**/*.js', './config/**/*.js',
'lib/*/index.js', './lib/*/index.js',
'server/**/*.js', './server/**/*.js',
], ],
parserOptions: { parserOptions: {
sourceType: 'script', sourceType: 'script',

View File

@ -35,7 +35,7 @@ export default class AuthDialog extends Component {
if (typeof prev !== 'undefined' && prev !== current) { if (typeof prev !== 'undefined' && prev !== current) {
type = 'use'; type = 'use';
} }
this.args.onchange({ data: get(this, 'token'), type: type }); this.args.onchange({ data: this.token, type: type });
} }
@action @action

View File

@ -22,7 +22,7 @@ export default Component.extend({
return !items.findBy('Name', term); return !items.findBy('Name', term);
}, },
add: function (name, changeset, value) { add: function (name, changeset, value) {
if (!(changeset.get(name) || []).includes(value) && value.isNew) { if (!(changeset.get(name) || []).includes(value)) {
changeset.pushObject(name, value); changeset.pushObject(name, value);
changeset.validate(); changeset.validate();
} }

View File

@ -47,7 +47,7 @@ export default Component.extend({
changeset: computed('item', function () { changeset: computed('item', function () {
const changeset = this.change.changesetFor(name, this.item || this.repo.create()); const changeset = this.change.changesetFor(name, this.item || this.repo.create());
if (changeset.isNew) { if (changeset.isPristine) {
changeset.validate(); changeset.validate();
} }
return changeset; return changeset;

View File

@ -4,7 +4,7 @@
*/ */
import Component from '@ember/component'; import Component from '@ember/component';
import { get, set } from '@ember/object'; import { set } from '@ember/object';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
export default Component.extend({ export default Component.extend({
@ -31,7 +31,7 @@ export default Component.extend({
set(item, 'Value', this.encoder.execute(target.value)); set(item, 'Value', this.encoder.execute(target.value));
break; break;
case 'additional': case 'additional':
parent = get(this, 'parent'); parent = this.parent;
set(item, 'Key', `${parent !== '/' ? parent : ''}${target.value}`); set(item, 'Key', `${parent !== '/' ? parent : ''}${target.value}`);
break; break;
case 'json': case 'json':

View File

@ -5,11 +5,9 @@
import Component from '@glimmer/component'; import Component from '@glimmer/component';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { computed, get, action } from '@ember/object'; import { computed, get, action, defineProperty } from '@ember/object';
import { alias } from '@ember/object/computed'; import { alias, sort } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking'; import { tracked } from '@glimmer/tracking';
import { sort } from '@ember/object/computed';
import { defineProperty } from '@ember/object';
export default class DataCollectionComponent extends Component { export default class DataCollectionComponent extends Component {
@service('filter') filter; @service('filter') filter;

View File

@ -37,12 +37,6 @@ export default Component.extend(Slotted, {
this._super(...arguments); this._super(...arguments);
set(this, 'hasError', this._isRegistered('error')); set(this, 'hasError', this._isRegistered('error'));
}, },
willDestroyElement: function () {
this._super(...arguments);
if (get(this, 'data.isNew')) {
this.data.rollbackAttributes();
}
},
actions: { actions: {
setData: function (data) { setData: function (data) {
let changeset = data; let changeset = data;

View File

@ -18,7 +18,7 @@ export default Component.extend(Slotted, {
didReceiveAttrs: function () { didReceiveAttrs: function () {
this._super(...arguments); this._super(...arguments);
if (typeof this.items !== 'undefined') { if (typeof this.items !== 'undefined') {
this.actions.change.apply(this, [this.items]); this.send('change', this.items);
} }
}, },
didInsertElement: function () { didInsertElement: function () {

View File

@ -34,8 +34,8 @@ export default Component.extend(Slotted, {
this._super(...arguments); this._super(...arguments);
this._cellLayout = this['cell-layout'] = new PercentageColumns( this._cellLayout = this['cell-layout'] = new PercentageColumns(
get(this, 'items.length'), get(this, 'items.length'),
get(this, 'columns'), this.columns,
get(this, 'cellHeight') this.cellHeight
); );
const o = this; const o = this;
this['cell-layout'].formatItemStyle = function (itemIndex) { this['cell-layout'].formatItemStyle = function (itemIndex) {
@ -51,14 +51,14 @@ export default Component.extend(Slotted, {
return {}; return {};
} }
return { return {
height: get(this, 'height'), height: this.height,
}; };
}), }),
actions: { actions: {
resize: function (e) { resize: function (e) {
// TODO: This top part is very similar to resize in tabular-collection // TODO: This top part is very similar to resize in tabular-collection
// see if it make sense to DRY out // see if it make sense to DRY out
const dom = get(this, 'dom'); const dom = this.dom;
const $footer = dom.element('footer[role="contentinfo"]'); const $footer = dom.element('footer[role="contentinfo"]');
if ($footer) { if ($footer) {
const border = 1; const border = 1;
@ -74,7 +74,7 @@ export default Component.extend(Slotted, {
return this.dom.clickFirstAnchor(e, '.list-collection > ul > li'); return this.dom.clickFirstAnchor(e, '.list-collection > ul > li');
}, },
change: function (index, e = {}) { change: function (index, e = {}) {
if (e.target.checked && index !== get(this, 'checked')) { if (e.target.checked && index !== this.checked) {
set(this, 'checked', parseInt(index)); set(this, 'checked', parseInt(index));
this.$row = this.dom.closest('li', e.target); this.$row = this.dom.closest('li', e.target);
this.$row.style.zIndex = 1; this.$row.style.zIndex = 1;

View File

@ -25,7 +25,7 @@ export default CollectionComponent.extend(Slotted, {
this.guid = this.dom.guid(this); this.guid = this.dom.guid(this);
// TODO: The row height should auto calculate properly from the CSS // TODO: The row height should auto calculate properly from the CSS
const o = this; const o = this;
this['cell-layout'] = new Grid(get(this, 'width'), get(this, 'rowHeight')); this['cell-layout'] = new Grid(this.width, this.rowHeight);
this['cell-layout'].formatItemStyle = function (itemIndex) { this['cell-layout'].formatItemStyle = function (itemIndex) {
let style = formatItemStyle.apply(this, arguments); let style = formatItemStyle.apply(this, arguments);
if (o.checked === itemIndex) { if (o.checked === itemIndex) {
@ -40,12 +40,12 @@ export default CollectionComponent.extend(Slotted, {
this.actions.resize.apply(this, [{ target: this.dom.viewport() }]); this.actions.resize.apply(this, [{ target: this.dom.viewport() }]);
}, },
style: computed('rowHeight', '_items', 'maxRows', 'maxHeight', function () { style: computed('rowHeight', '_items', 'maxRows', 'maxHeight', function () {
const maxRows = get(this, 'rows'); const maxRows = this.rows;
let height = get(this, 'maxHeight'); let height = this.maxHeight;
if (maxRows) { if (maxRows) {
let rows = Math.max(3, get(this._items || [], 'length')); let rows = Math.max(3, get(this._items || [], 'length'));
rows = Math.min(maxRows, rows); rows = Math.min(maxRows, rows);
height = get(this, 'rowHeight') * rows + 29; height = this.rowHeight * rows + 29;
} }
return { return {
height: height, height: height,
@ -80,7 +80,7 @@ export default CollectionComponent.extend(Slotted, {
const height = e.target.innerHeight - space; const height = e.target.innerHeight - space;
this.set('maxHeight', Math.max(0, height)); this.set('maxHeight', Math.max(0, height));
// TODO: The row height should auto calculate properly from the CSS // TODO: The row height should auto calculate properly from the CSS
this['cell-layout'] = new Grid($appContent.clientWidth, get(this, 'rowHeight')); this['cell-layout'] = new Grid($appContent.clientWidth, this.rowHeight);
const o = this; const o = this;
this['cell-layout'].formatItemStyle = function (itemIndex) { this['cell-layout'].formatItemStyle = function (itemIndex) {
let style = formatItemStyle.apply(this, arguments); let style = formatItemStyle.apply(this, arguments);
@ -100,7 +100,7 @@ export default CollectionComponent.extend(Slotted, {
if (this.$tr) { if (this.$tr) {
this.$tr.style.zIndex = null; this.$tr.style.zIndex = null;
} }
if (e.target && e.target.checked && index !== get(this, 'checked')) { if (e.target && e.target.checked && index !== this.checked) {
set(this, 'checked', parseInt(index)); set(this, 'checked', parseInt(index));
const target = e.target; const target = e.target;
const $tr = this.dom.closest('tr', target); const $tr = this.dom.closest('tr', target);

View File

@ -5,11 +5,11 @@
import { runInDebug } from '@ember/debug'; import { runInDebug } from '@ember/debug';
import require from 'require'; import require from 'require';
import merge from 'deepmerge'; import assign from 'deepmerge';
const doc = document; const doc = document;
export const services = merge.all( export const services = assign.all(
[...doc.querySelectorAll(`script[data-services]`)].map(($item) => [...doc.querySelectorAll(`script[data-services]`)].map(($item) =>
JSON.parse($item.dataset[`services`]) JSON.parse($item.dataset[`services`])
) )

View File

@ -3,8 +3,7 @@
* SPDX-License-Identifier: MPL-2.0 * SPDX-License-Identifier: MPL-2.0
*/ */
import Model from 'ember-data/model'; import Model, { attr } from '@ember-data/model';
import attr from 'ember-data/attr';
export const PRIMARY_KEY = 'uid'; export const PRIMARY_KEY = 'uid';
export const SLUG_KEY = 'Name'; export const SLUG_KEY = 'Name';

View File

@ -31,6 +31,7 @@ export default class WithCopyableModifier extends Modifier {
this.source = this.clipboard this.source = this.clipboard
.execute(this.element, { .execute(this.element, {
text: (_) => value, text: (_) => value,
container: this.element,
...hash.options, ...hash.options,
}) })
.on('success', hash.success) .on('success', hash.success)

View File

@ -7,14 +7,14 @@
import EmberRouter from '@ember/routing/router'; import EmberRouter from '@ember/routing/router';
import config from './config/environment'; import config from './config/environment';
import { runInDebug } from '@ember/debug'; import { runInDebug } from '@ember/debug';
import merge from 'deepmerge'; import assign from 'deepmerge';
import { env } from 'consul-ui/env'; import { env } from 'consul-ui/env';
import walk, { dump } from 'consul-ui/utils/routing/walk'; import walk, { dump } from 'consul-ui/utils/routing/walk';
const doc = document; const doc = document;
const appName = config.modulePrefix; const appName = config.modulePrefix;
export const routes = merge.all( export const routes = assign.all(
[...doc.querySelectorAll(`script[data-routes]`)].map(($item) => [...doc.querySelectorAll(`script[data-routes]`)].map(($item) =>
JSON.parse($item.dataset[`routes`]) JSON.parse($item.dataset[`routes`])
) )

View File

@ -143,6 +143,6 @@ export default class BaseRoute extends Route {
if (typeof obj !== 'undefined' && !Array.isArray(obj) && typeof obj !== 'string') { if (typeof obj !== 'undefined' && !Array.isArray(obj) && typeof obj !== 'string') {
params = Object.values(obj); params = Object.values(obj);
} }
return super.transitionTo(routeName, ...params); return this.router.transitionTo(routeName, ...params);
} }
} }

View File

@ -14,24 +14,22 @@ export default class OAuth2CodeWithURLProvider extends OAuth2CodeProvider {
} }
open(options) { open(options) {
const name = this.get('name'), const name = this.name,
url = this.buildUrl(), url = this.buildUrl(),
responseParams = ['state', 'code'], responseParams = ['state', 'code'],
responseType = 'code'; responseType = 'code';
return this.get('popup') return this.popup.open(url, responseParams, options).then(function (authData) {
.open(url, responseParams, options) // the same as the parent class but with an authorizationState added
.then(function (authData) { const creds = {
// the same as the parent class but with an authorizationState added authorizationState: authData.state,
const creds = { authorizationCode: decodeURIComponent(authData[responseType]),
authorizationState: authData.state, provider: name,
authorizationCode: decodeURIComponent(authData[responseType]), };
provider: name, runInDebug((_) =>
}; console.info('Retrieved the following creds from the OAuth Provider', creds)
runInDebug((_) => );
console.info('Retrieved the following creds from the OAuth Provider', creds) return creds;
); });
return creds;
});
} }
close() { close() {

View File

@ -9,13 +9,13 @@
<route.Announcer @title='Consul' /> <route.Announcer @title='Consul' />
{{! Tell CSS what we have enabled }} {{! Tell CSS what we have enabled }}
{{#if (can 'use acls')}} {{#if (can 'use acls')}}
{{document-attrs class='has-acls'}} {{document-attrs class="has-acls"}}
{{/if}} {{/if}}
{{#if (can 'use nspaces')}} {{#if (can 'use nspaces')}}
{{document-attrs class='has-nspaces'}} {{document-attrs class="has-nspaces" }}
{{/if}} {{/if}}
{{#if (can 'use partitions')}} {{#if (can 'use partitions')}}
{{document-attrs class='has-partitions'}} {{document-attrs class="has-partitions" }}
{{/if}} {{/if}}
{{! Listen out for blocking query/client setting changes }} {{! Listen out for blocking query/client setting changes }}
@ -28,7 +28,7 @@
<DataSource @src={{uri 'settings://consul:theme'}} as |source|> <DataSource @src={{uri 'settings://consul:theme'}} as |source|>
{{#each-in source.data as |key value|}} {{#each-in source.data as |key value|}}
{{#if (and value (includes key (array 'color-scheme' 'contrast')))}} {{#if (and value (includes key (array 'color-scheme' 'contrast')))}}
{{document-attrs class=(concat 'prefers-' key '-' value)}} {{document-attrs class=(concat "prefers-" key "-" value) }}
{{/if}} {{/if}}
{{/each-in}} {{/each-in}}
</DataSource> </DataSource>

View File

@ -5,16 +5,16 @@
{{page-title 'Engineering Docs - Consul' separator=' - '}} {{page-title 'Engineering Docs - Consul' separator=' - '}}
{{document-attrs class="is-debug"}} {{document-attrs class="is-debug" }}
{{! Tell CSS what we have enabled }} {{! Tell CSS what we have enabled }}
{{#if (can "use acls")}} {{#if (can "use acls")}}
{{document-attrs class="has-acls"}} {{document-attrs class="has-acls" }}
{{/if}} {{/if}}
{{#if (can "use nspaces")}} {{#if (can "use nspaces")}}
{{document-attrs class="has-nspaces"}} {{document-attrs class="has-nspaces" }}
{{/if}} {{/if}}
{{#if (can "use partitions")}} {{#if (can "use partitions")}}
{{document-attrs class="has-partitions"}} {{document-attrs class="has-partitions" }}
{{/if}} {{/if}}
<App class="docs" id="wrapper"> <App class="docs" id="wrapper">

View File

@ -3,7 +3,7 @@
"packages": [ "packages": [
{ {
"name": "ember-cli", "name": "ember-cli",
"version": "3.27.0", "version": "3.28.6",
"blueprints": [ "blueprints": [
{ {
"name": "app", "name": "app",

View File

@ -64,7 +64,7 @@
"@docfy/ember": "^0.4.1", "@docfy/ember": "^0.4.1",
"@ember/optional-features": "^2.0.0", "@ember/optional-features": "^2.0.0",
"@ember/render-modifiers": "^1.0.2", "@ember/render-modifiers": "^1.0.2",
"@ember/test-helpers": "^2.2.5", "@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4", "@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4", "@glimmer/tracking": "^1.0.4",
"@hashicorp/design-system-components": "^1.6.0", "@hashicorp/design-system-components": "^1.6.0",
@ -87,7 +87,7 @@
"broccoli-funnel": "^3.0.3", "broccoli-funnel": "^3.0.3",
"broccoli-merge-trees": "^4.2.0", "broccoli-merge-trees": "^4.2.0",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"clipboard": "^2.0.4", "clipboard": "^2.0.11",
"consul-acls": "*", "consul-acls": "*",
"consul-hcp": "*", "consul-hcp": "*",
"consul-lock-sessions": "*", "consul-lock-sessions": "*",
@ -108,15 +108,15 @@
"ember-auto-import": "^2.4.2", "ember-auto-import": "^2.4.2",
"ember-can": "^4.2.0", "ember-can": "^4.2.0",
"ember-changeset-validations": "~3.15.2", "ember-changeset-validations": "~3.15.2",
"ember-cli": "~3.27.0", "ember-cli": "3.28.6",
"ember-cli-app-version": "^5.0.0", "ember-cli-app-version": "^5.0.0",
"ember-cli-babel": "^7.26.6", "ember-cli-babel": "^7.26.10",
"ember-cli-code-coverage": "^1.0.0-beta.4", "ember-cli-code-coverage": "^1.0.0-beta.4",
"ember-cli-dependency-checker": "^3.2.0", "ember-cli-dependency-checker": "^3.2.0",
"ember-cli-deprecation-workflow": "^2.1.0", "ember-cli-deprecation-workflow": "^2.1.0",
"ember-cli-flash": "^2.1.1", "ember-cli-flash": "^2.1.1",
"ember-cli-htmlbars": "^5.7.1", "ember-cli-htmlbars": "^5.7.2",
"ember-cli-inject-live-reload": "^2.0.2", "ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-page-object": "^1.17.11", "ember-cli-page-object": "^1.17.11",
"ember-cli-postcss": "^8.1.0", "ember-cli-postcss": "^8.1.0",
"ember-cli-sri": "^2.1.1", "ember-cli-sri": "^2.1.1",
@ -127,7 +127,7 @@
"ember-collection": "^1.0.0", "ember-collection": "^1.0.0",
"ember-compatibility-helpers": "^1.2.5", "ember-compatibility-helpers": "^1.2.5",
"ember-composable-helpers": "^5.0.0", "ember-composable-helpers": "^5.0.0",
"ember-data": "~3.27.1", "ember-data": "~3.28.6",
"ember-data-model-fragments": "5.0.0-beta.8", "ember-data-model-fragments": "5.0.0-beta.8",
"ember-decorators": "^6.1.1", "ember-decorators": "^6.1.1",
"ember-exam": "^6.1.0", "ember-exam": "^6.1.0",
@ -145,25 +145,25 @@
"ember-page-title": "^6.2.2", "ember-page-title": "^6.2.2",
"ember-power-select": "^4.0.5", "ember-power-select": "^4.0.5",
"ember-power-select-with-create": "^0.8.0", "ember-power-select-with-create": "^0.8.0",
"ember-qunit": "^5.1.4", "ember-qunit": "^5.1.5",
"ember-ref-bucket": "^4.1.0", "ember-ref-bucket": "^4.1.0",
"ember-render-helpers": "^0.2.0", "ember-render-helpers": "^0.2.0",
"ember-resolver": "^8.0.2", "ember-resolver": "^8.0.3",
"ember-route-action-helper": "^2.0.8", "ember-route-action-helper": "^2.0.8",
"ember-router-helpers": "^0.4.0", "ember-router-helpers": "^0.4.0",
"ember-set-helper": "^2.0.0", "ember-set-helper": "^2.0.0",
"ember-sinon-qunit": "5.0.0", "ember-sinon-qunit": "5.0.0",
"ember-source": "~3.27.2", "ember-source": "3.28.8",
"ember-stargate": "^0.2.0", "ember-stargate": "^0.2.0",
"ember-string-fns": "^1.4.0", "ember-string-fns": "^1.4.0",
"ember-test-selectors": "^5.0.0", "ember-test-selectors": "^5.0.0",
"ember-truth-helpers": "^3.0.0", "ember-truth-helpers": "^3.0.0",
"eslint": "^7.27.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.4.2", "eslint-plugin-ember": "^10.5.8",
"eslint-plugin-node": "^11.0.0", "eslint-plugin-node": "^11.0.0",
"eslint-plugin-prettier": "^3.4.0", "eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-qunit": "^6.1.1", "eslint-plugin-qunit": "^6.2.0",
"faker": "^5.5.3", "faker": "^5.5.3",
"flat": "^5.0.0", "flat": "^5.0.0",
"hast-util-to-string": "^1.0.4", "hast-util-to-string": "^1.0.4",
@ -177,9 +177,9 @@
"ngraph.graph": "^19.1.0", "ngraph.graph": "^19.1.0",
"parse-duration": "^1.0.0", "parse-duration": "^1.0.0",
"pretender": "^3.2.0", "pretender": "^3.2.0",
"prettier": "^2.3.0", "prettier": "^2.5.1",
"pretty-ms": "^7.0.1", "pretty-ms": "^7.0.1",
"qunit": "^2.15.0", "qunit": "^2.17.2",
"qunit-dom": "^1.6.0", "qunit-dom": "^1.6.0",
"react-is": "^17.0.1", "react-is": "^17.0.1",
"refractor": "^3.5.0", "refractor": "^3.5.0",
@ -197,7 +197,7 @@
"webpack": "^5.74.0" "webpack": "^5.74.0"
}, },
"engines": { "engines": {
"node": ">=10 <=14" "node": ">=14 <=16"
}, },
"ember": { "ember": {
"edition": "octane" "edition": "octane"
@ -213,5 +213,8 @@
}, },
"volta": { "volta": {
"node": "14.20.1" "node": "14.20.1"
},
"dependencies": {
"doctoc": "^2.0.0"
} }
} }

File diff suppressed because it is too large Load Diff