mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
SIP-32: Moving frontend code to the base of the repo (#9098)
* move assets out, get webpack dev working * update docs to reference superset-frontend * draw the rest of the owl * fix docs * fix webpack script * rats * correct docs * fix tox dox
This commit is contained in:
committed by
GitHub
parent
0cf354cc88
commit
2913063924
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import componentIsResizable from '../../../../src/dashboard/util/componentIsResizable';
|
||||
import {
|
||||
CHART_TYPE,
|
||||
COLUMN_TYPE,
|
||||
DASHBOARD_GRID_TYPE,
|
||||
DASHBOARD_ROOT_TYPE,
|
||||
DIVIDER_TYPE,
|
||||
HEADER_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
const notResizable = [
|
||||
DASHBOARD_GRID_TYPE,
|
||||
DASHBOARD_ROOT_TYPE,
|
||||
DIVIDER_TYPE,
|
||||
HEADER_TYPE,
|
||||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
];
|
||||
|
||||
const resizable = [COLUMN_TYPE, CHART_TYPE, MARKDOWN_TYPE];
|
||||
|
||||
describe('componentIsResizable', () => {
|
||||
resizable.forEach(type => {
|
||||
it(`should return true for ${type}`, () => {
|
||||
expect(componentIsResizable({ type })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
notResizable.forEach(type => {
|
||||
it(`should return false for ${type}`, () => {
|
||||
expect(componentIsResizable({ type })).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import reorderItem from '../../../../src/dashboard/util/dnd-reorder';
|
||||
|
||||
describe('dnd-reorderItem', () => {
|
||||
it('should remove the item from its source entity and add it to its destination entity', () => {
|
||||
const result = reorderItem({
|
||||
entitiesMap: {
|
||||
a: {
|
||||
id: 'a',
|
||||
children: ['x', 'y', 'z'],
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
children: ['banana'],
|
||||
},
|
||||
},
|
||||
source: { id: 'a', index: 2 },
|
||||
destination: { id: 'b', index: 1 },
|
||||
});
|
||||
|
||||
expect(result.a.children).toEqual(['x', 'y']);
|
||||
expect(result.b.children).toEqual(['banana', 'z']);
|
||||
});
|
||||
|
||||
it('should correctly move elements within the same list', () => {
|
||||
const result = reorderItem({
|
||||
entitiesMap: {
|
||||
a: {
|
||||
id: 'a',
|
||||
children: ['x', 'y', 'z'],
|
||||
},
|
||||
},
|
||||
source: { id: 'a', index: 2 },
|
||||
destination: { id: 'a', index: 0 },
|
||||
});
|
||||
|
||||
expect(result.a.children).toEqual(['z', 'x', 'y']);
|
||||
});
|
||||
|
||||
it('should copy items that do not move into the result', () => {
|
||||
const extraEntity = {};
|
||||
const result = reorderItem({
|
||||
entitiesMap: {
|
||||
a: {
|
||||
id: 'a',
|
||||
children: ['x', 'y', 'z'],
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
children: ['banana'],
|
||||
},
|
||||
iAmExtra: extraEntity,
|
||||
},
|
||||
source: { id: 'a', index: 2 },
|
||||
destination: { id: 'b', index: 1 },
|
||||
});
|
||||
|
||||
expect(result.iAmExtra === extraEntity).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import dropOverflowsParent from '../../../../src/dashboard/util/dropOverflowsParent';
|
||||
import { NEW_COMPONENTS_SOURCE_ID } from '../../../../src/dashboard/util/constants';
|
||||
import {
|
||||
CHART_TYPE,
|
||||
COLUMN_TYPE,
|
||||
ROW_TYPE,
|
||||
HEADER_TYPE,
|
||||
TAB_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
describe('dropOverflowsParent', () => {
|
||||
it('returns true if a parent does NOT have adequate width for child', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'a' },
|
||||
dragging: { id: 'z' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: ROW_TYPE,
|
||||
children: ['b', 'b', 'b', 'b'], // width = 4x bs = 12
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 3,
|
||||
},
|
||||
},
|
||||
z: {
|
||||
id: 'z',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if a parent DOES have adequate width for child', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'a' },
|
||||
dragging: { id: 'z' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: ROW_TYPE,
|
||||
children: ['b', 'b'],
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 3,
|
||||
},
|
||||
},
|
||||
z: {
|
||||
id: 'z',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if a child CAN shrink to available parent space', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'a' },
|
||||
dragging: { id: 'z' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: ROW_TYPE,
|
||||
children: ['b', 'b'], // 2x b = 10
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 5,
|
||||
},
|
||||
},
|
||||
z: {
|
||||
id: 'z',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 10,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true if a child CANNOT shrink to available parent space', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'a' },
|
||||
dragging: { id: 'b' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: COLUMN_TYPE,
|
||||
meta: {
|
||||
width: 6,
|
||||
},
|
||||
},
|
||||
// rows with children cannot shrink
|
||||
b: {
|
||||
id: 'b',
|
||||
type: ROW_TYPE,
|
||||
children: ['bChild', 'bChild', 'bChild'],
|
||||
},
|
||||
bChild: {
|
||||
id: 'bChild',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true if a column has children that CANNOT shrink to available parent space', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'destination' },
|
||||
dragging: { id: 'dragging' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
destination: {
|
||||
id: 'destination',
|
||||
type: ROW_TYPE,
|
||||
children: ['b', 'b'], // 2x b = 10, 2 available
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
type: CHART_TYPE,
|
||||
meta: {
|
||||
width: 5,
|
||||
},
|
||||
},
|
||||
dragging: {
|
||||
id: 'dragging',
|
||||
type: COLUMN_TYPE,
|
||||
meta: {
|
||||
width: 10,
|
||||
},
|
||||
children: ['rowWithChildren'], // 2x b = width 10
|
||||
},
|
||||
rowWithChildren: {
|
||||
id: 'rowWithChildren',
|
||||
type: ROW_TYPE,
|
||||
children: ['b', 'b'],
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(true);
|
||||
// remove children
|
||||
expect(
|
||||
dropOverflowsParent(dropResult, {
|
||||
...layout,
|
||||
dragging: { ...layout.dragging, children: [] },
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should work with new components that are not in the layout', () => {
|
||||
const dropResult = {
|
||||
source: { id: NEW_COMPONENTS_SOURCE_ID },
|
||||
destination: { id: 'a' },
|
||||
dragging: { type: CHART_TYPE },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: ROW_TYPE,
|
||||
children: [],
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(false);
|
||||
});
|
||||
|
||||
it('source/destination without widths should not overflow parent', () => {
|
||||
const dropResult = {
|
||||
source: { id: '_' },
|
||||
destination: { id: 'tab' },
|
||||
dragging: { id: 'header' },
|
||||
};
|
||||
|
||||
const layout = {
|
||||
tab: {
|
||||
id: 'tab',
|
||||
type: TAB_TYPE,
|
||||
},
|
||||
header: {
|
||||
id: 'header',
|
||||
type: HEADER_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
expect(dropOverflowsParent(dropResult, layout)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import findFirstParentContainerId from '../../../../src/dashboard/util/findFirstParentContainer';
|
||||
import {
|
||||
DASHBOARD_GRID_ID,
|
||||
DASHBOARD_ROOT_ID,
|
||||
} from '../../../../src/dashboard/util/constants';
|
||||
|
||||
describe('findFirstParentContainer', () => {
|
||||
const mockGridLayout = {
|
||||
DASHBOARD_VERSION_KEY: 'v2',
|
||||
ROOT_ID: {
|
||||
type: 'ROOT',
|
||||
id: 'ROOT_ID',
|
||||
children: ['GRID_ID'],
|
||||
},
|
||||
GRID_ID: {
|
||||
type: 'GRID',
|
||||
id: 'GRID_ID',
|
||||
children: ['ROW-Bk45URrlQ'],
|
||||
},
|
||||
'ROW-Bk45URrlQ': {
|
||||
type: 'ROW',
|
||||
id: 'ROW-Bk45URrlQ',
|
||||
children: ['CHART-ryxVc8RHlX'],
|
||||
},
|
||||
'CHART-ryxVc8RHlX': {
|
||||
type: 'CHART',
|
||||
id: 'CHART-ryxVc8RHlX',
|
||||
children: [],
|
||||
},
|
||||
HEADER_ID: {
|
||||
id: 'HEADER_ID',
|
||||
type: 'HEADER',
|
||||
},
|
||||
};
|
||||
const mockTabsLayout = {
|
||||
'CHART-S1gilYABe7': {
|
||||
children: [],
|
||||
id: 'CHART-S1gilYABe7',
|
||||
type: 'CHART',
|
||||
},
|
||||
'CHART-SJli5K0HlQ': {
|
||||
children: [],
|
||||
id: 'CHART-SJli5K0HlQ',
|
||||
type: 'CHART',
|
||||
},
|
||||
GRID_ID: {
|
||||
children: [],
|
||||
id: 'GRID_ID',
|
||||
type: 'GRID',
|
||||
},
|
||||
HEADER_ID: {
|
||||
id: 'HEADER_ID',
|
||||
type: 'HEADER',
|
||||
},
|
||||
ROOT_ID: {
|
||||
children: ['TABS-SkgJ5t0Bem'],
|
||||
id: 'ROOT_ID',
|
||||
type: 'ROOT',
|
||||
},
|
||||
'ROW-S1B8-JLgX': {
|
||||
children: ['CHART-SJli5K0HlQ'],
|
||||
id: 'ROW-S1B8-JLgX',
|
||||
type: 'ROW',
|
||||
},
|
||||
'ROW-S1bUb1Ilm': {
|
||||
children: ['CHART-S1gilYABe7'],
|
||||
id: 'ROW-S1bUb1Ilm',
|
||||
type: 'ROW',
|
||||
},
|
||||
'TABS-ByeLSWyLe7': {
|
||||
children: ['TAB-BJbLSZ1UeQ'],
|
||||
id: 'TABS-ByeLSWyLe7',
|
||||
type: 'TABS',
|
||||
},
|
||||
'TABS-SkgJ5t0Bem': {
|
||||
children: ['TAB-HkWJcFCHxQ', 'TAB-ByDBbkLlQ'],
|
||||
id: 'TABS-SkgJ5t0Bem',
|
||||
meta: {},
|
||||
type: 'TABS',
|
||||
},
|
||||
'TAB-BJbLSZ1UeQ': {
|
||||
children: ['ROW-S1bUb1Ilm'],
|
||||
id: 'TAB-BJbLSZ1UeQ',
|
||||
type: 'TAB',
|
||||
},
|
||||
'TAB-ByDBbkLlQ': {
|
||||
children: ['ROW-S1B8-JLgX'],
|
||||
id: 'TAB-ByDBbkLlQ',
|
||||
type: 'TAB',
|
||||
},
|
||||
'TAB-HkWJcFCHxQ': {
|
||||
children: ['TABS-ByeLSWyLe7'],
|
||||
id: 'TAB-HkWJcFCHxQ',
|
||||
type: 'TAB',
|
||||
},
|
||||
DASHBOARD_VERSION_KEY: 'v2',
|
||||
};
|
||||
|
||||
it('should return grid root', () => {
|
||||
expect(findFirstParentContainerId(mockGridLayout)).toBe(DASHBOARD_GRID_ID);
|
||||
});
|
||||
|
||||
it('should return first tab', () => {
|
||||
const tabsId = mockTabsLayout[DASHBOARD_ROOT_ID].children[0];
|
||||
const firstTabId = mockTabsLayout[tabsId].children[0];
|
||||
expect(findFirstParentContainerId(mockTabsLayout)).toBe(firstTabId);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import findParentId from '../../../../src/dashboard/util/findParentId';
|
||||
|
||||
describe('findParentId', () => {
|
||||
const layout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
children: ['b', 'r', 'k'],
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
children: ['x', 'y', 'z'],
|
||||
},
|
||||
z: {
|
||||
id: 'z',
|
||||
children: [],
|
||||
},
|
||||
};
|
||||
it('should return the correct parentId', () => {
|
||||
expect(findParentId({ childId: 'b', layout })).toBe('a');
|
||||
expect(findParentId({ childId: 'z', layout })).toBe('b');
|
||||
});
|
||||
|
||||
it('should return null if the parent cannot be found', () => {
|
||||
expect(findParentId({ childId: 'a', layout })).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* 'License'); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import findTabIndexByComponentId from '../../../../src/dashboard/util/findTabIndexByComponentId';
|
||||
|
||||
describe('findTabIndexByComponentId', () => {
|
||||
const topLevelTabsComponent = {
|
||||
children: ['TAB-0g-5l347I2', 'TAB-qrwN_9VB5'],
|
||||
id: 'TABS-MNQQSW-kyd',
|
||||
meta: {},
|
||||
parents: ['ROOT_ID'],
|
||||
type: 'TABS',
|
||||
};
|
||||
const rowLevelTabsComponent = {
|
||||
children: [
|
||||
'TAB-TwyUUGp2Bg',
|
||||
'TAB-Zl1BQAUvN',
|
||||
'TAB-P0DllxzTU',
|
||||
'TAB---e53RNei',
|
||||
],
|
||||
id: 'TABS-Oduxop1L7I',
|
||||
meta: {},
|
||||
parents: ['ROOT_ID', 'TABS-MNQQSW-kyd', 'TAB-qrwN_9VB5'],
|
||||
type: 'TABS',
|
||||
};
|
||||
const goodPathToChild = [
|
||||
'ROOT_ID',
|
||||
'TABS-MNQQSW-kyd',
|
||||
'TAB-qrwN_9VB5',
|
||||
'TABS-Oduxop1L7I',
|
||||
'TAB-P0DllxzTU',
|
||||
'ROW-JXhrFnVP8',
|
||||
'CHART-dUIVg-ENq6',
|
||||
];
|
||||
const badPath = ['ROOT_ID', 'TABS-MNQQSW-kyd', 'TAB-ABC', 'TABS-Oduxop1L7I'];
|
||||
|
||||
it('should return -1 if no directPathToChild', () => {
|
||||
expect(
|
||||
findTabIndexByComponentId({
|
||||
currentComponent: topLevelTabsComponent,
|
||||
directPathToChild: [],
|
||||
}),
|
||||
).toBe(-1);
|
||||
});
|
||||
|
||||
it('should return -1 if not found tab id', () => {
|
||||
expect(
|
||||
findTabIndexByComponentId({
|
||||
currentComponent: topLevelTabsComponent,
|
||||
directPathToChild: badPath,
|
||||
}),
|
||||
).toBe(-1);
|
||||
});
|
||||
|
||||
it('should return children index if matched an id in the path', () => {
|
||||
expect(
|
||||
findTabIndexByComponentId({
|
||||
currentComponent: topLevelTabsComponent,
|
||||
directPathToChild: goodPathToChild,
|
||||
}),
|
||||
).toBe(1);
|
||||
|
||||
expect(
|
||||
findTabIndexByComponentId({
|
||||
currentComponent: rowLevelTabsComponent,
|
||||
directPathToChild: goodPathToChild,
|
||||
}),
|
||||
).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getChartAndLabelComponentIdFromPath from '../../../../src/dashboard/util/getChartAndLabelComponentIdFromPath';
|
||||
|
||||
describe('getChartAndLabelComponentIdFromPath', () => {
|
||||
it('should return label and component id', () => {
|
||||
const directPathToChild = [
|
||||
'ROOT_ID',
|
||||
'TABS-aX1uNK-ryo',
|
||||
'TAB-ZRgxfD2ktj',
|
||||
'ROW-46632bc2',
|
||||
'COLUMN-XjlxaS-flc',
|
||||
'CHART-x-RMdAtlDb',
|
||||
'LABEL-region',
|
||||
];
|
||||
|
||||
expect(getChartAndLabelComponentIdFromPath(directPathToChild)).toEqual({
|
||||
label: 'LABEL-region',
|
||||
chart: 'CHART-x-RMdAtlDb',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getChartIdsFromLayout from '../../../../src/dashboard/util/getChartIdsFromLayout';
|
||||
import {
|
||||
ROW_TYPE,
|
||||
CHART_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
describe('getChartIdsFromLayout', () => {
|
||||
const mockLayout = {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: CHART_TYPE,
|
||||
meta: { chartId: 'A' },
|
||||
},
|
||||
b: {
|
||||
id: 'b',
|
||||
type: CHART_TYPE,
|
||||
meta: { chartId: 'B' },
|
||||
},
|
||||
c: {
|
||||
id: 'c',
|
||||
type: ROW_TYPE,
|
||||
meta: { chartId: 'C' },
|
||||
},
|
||||
};
|
||||
|
||||
it('should return an array of chartIds', () => {
|
||||
const result = getChartIdsFromLayout(mockLayout);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.includes('A')).toBe(true);
|
||||
expect(result.includes('B')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return ids only from CHART_TYPE components', () => {
|
||||
const result = getChartIdsFromLayout(mockLayout);
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result.includes('C')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getDashboardUrl from '../../../../src/dashboard/util/getDashboardUrl';
|
||||
import { DASHBOARD_FILTER_SCOPE_GLOBAL } from '../../../../src/dashboard/reducers/dashboardFilters';
|
||||
|
||||
describe('getChartIdsFromLayout', () => {
|
||||
it('should encode filters', () => {
|
||||
const filters = {
|
||||
'35_key': {
|
||||
values: ['value'],
|
||||
scope: DASHBOARD_FILTER_SCOPE_GLOBAL,
|
||||
},
|
||||
};
|
||||
const url = getDashboardUrl('path', filters);
|
||||
expect(url).toBe(
|
||||
'path?preselect_filters=%7B%2235%22%3A%7B%22key%22%3A%5B%22value%22%5D%7D%7D',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getDetailedComponentWidth from '../../../../src/dashboard/util/getDetailedComponentWidth';
|
||||
import * as types from '../../../../src/dashboard/util/componentTypes';
|
||||
import {
|
||||
GRID_COLUMN_COUNT,
|
||||
GRID_MIN_COLUMN_COUNT,
|
||||
} from '../../../../src/dashboard/util/constants';
|
||||
|
||||
describe('getDetailedComponentWidth', () => {
|
||||
it('should return an object with width, minimumWidth, and occupiedWidth', () => {
|
||||
expect(
|
||||
Object.keys(getDetailedComponentWidth({ id: '_', components: {} })),
|
||||
).toEqual(
|
||||
expect.arrayContaining(['minimumWidth', 'occupiedWidth', 'width']),
|
||||
);
|
||||
});
|
||||
|
||||
describe('width', () => {
|
||||
it('should be undefined if the component is not resizable and has no defined width', () => {
|
||||
const empty = {
|
||||
width: undefined,
|
||||
occupiedWidth: undefined,
|
||||
minimumWidth: undefined,
|
||||
};
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.HEADER_TYPE },
|
||||
}),
|
||||
).toEqual(empty);
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.DIVIDER_TYPE },
|
||||
}),
|
||||
).toEqual(empty);
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.TAB_TYPE },
|
||||
}),
|
||||
).toEqual(empty);
|
||||
});
|
||||
|
||||
it('should match component meta width for resizeable components', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.CHART_TYPE, meta: { width: 1 } },
|
||||
}),
|
||||
).toEqual({ width: 1, occupiedWidth: 1, minimumWidth: 1 });
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.MARKDOWN_TYPE, meta: { width: 2 } },
|
||||
}),
|
||||
).toEqual({ width: 2, occupiedWidth: 2, minimumWidth: 1 });
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.COLUMN_TYPE, meta: { width: 3 } },
|
||||
}),
|
||||
// note: occupiedWidth is zero for colunns/see test below
|
||||
).toEqual({ width: 3, occupiedWidth: 0, minimumWidth: 1 });
|
||||
});
|
||||
|
||||
it('should be GRID_COLUMN_COUNT for row components WITHOUT parents', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'row',
|
||||
components: { row: { id: 'row', type: types.ROW_TYPE } },
|
||||
}),
|
||||
).toEqual({
|
||||
width: GRID_COLUMN_COUNT,
|
||||
occupiedWidth: 0,
|
||||
minimumWidth: GRID_MIN_COLUMN_COUNT,
|
||||
});
|
||||
});
|
||||
|
||||
it('should match parent width for row components WITH parents', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'row',
|
||||
components: {
|
||||
row: { id: 'row', type: types.ROW_TYPE },
|
||||
parent: {
|
||||
id: 'parent',
|
||||
type: types.COLUMN_TYPE,
|
||||
children: ['row'],
|
||||
meta: { width: 7 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
width: 7,
|
||||
occupiedWidth: 0,
|
||||
minimumWidth: GRID_MIN_COLUMN_COUNT,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use either id or component (to support new components)', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'id',
|
||||
components: {
|
||||
id: { id: 'id', type: types.CHART_TYPE, meta: { width: 6 } },
|
||||
},
|
||||
}).width,
|
||||
).toBe(6);
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: 'id', type: types.CHART_TYPE, meta: { width: 6 } },
|
||||
}).width,
|
||||
).toBe(6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('occupiedWidth', () => {
|
||||
it('should reflect the sum of child widths for row components', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'row',
|
||||
components: {
|
||||
row: {
|
||||
id: 'row',
|
||||
type: types.ROW_TYPE,
|
||||
children: ['child', 'child'],
|
||||
},
|
||||
child: { id: 'child', meta: { width: 3.5 } },
|
||||
},
|
||||
}),
|
||||
).toEqual({ width: 12, occupiedWidth: 7, minimumWidth: 7 });
|
||||
});
|
||||
|
||||
it('should always be zero for column components', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.COLUMN_TYPE, meta: { width: 2 } },
|
||||
}),
|
||||
).toEqual({ width: 2, occupiedWidth: 0, minimumWidth: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('minimumWidth', () => {
|
||||
it('should equal GRID_MIN_COLUMN_COUNT for resizable components', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.CHART_TYPE, meta: { width: 1 } },
|
||||
}),
|
||||
).toEqual({
|
||||
width: 1,
|
||||
minimumWidth: GRID_MIN_COLUMN_COUNT,
|
||||
occupiedWidth: 1,
|
||||
});
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.MARKDOWN_TYPE, meta: { width: 2 } },
|
||||
}),
|
||||
).toEqual({
|
||||
width: 2,
|
||||
minimumWidth: GRID_MIN_COLUMN_COUNT,
|
||||
occupiedWidth: 2,
|
||||
});
|
||||
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
component: { id: '', type: types.COLUMN_TYPE, meta: { width: 3 } },
|
||||
}),
|
||||
).toEqual({
|
||||
width: 3,
|
||||
minimumWidth: GRID_MIN_COLUMN_COUNT,
|
||||
occupiedWidth: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should equal the width of row children for column components with row children', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'column',
|
||||
components: {
|
||||
column: {
|
||||
id: 'column',
|
||||
type: types.COLUMN_TYPE,
|
||||
children: ['rowChild', 'ignoredChartChild'],
|
||||
meta: { width: 12 },
|
||||
},
|
||||
rowChild: {
|
||||
id: 'rowChild',
|
||||
type: types.ROW_TYPE,
|
||||
children: ['rowChildChild', 'rowChildChild'],
|
||||
},
|
||||
rowChildChild: {
|
||||
id: 'rowChildChild',
|
||||
meta: { width: 3.5 },
|
||||
},
|
||||
ignoredChartChild: {
|
||||
id: 'ignoredChartChild',
|
||||
meta: { width: 100 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
// occupiedWidth is zero for colunns/see test below
|
||||
).toEqual({ width: 12, occupiedWidth: 0, minimumWidth: 7 });
|
||||
});
|
||||
|
||||
it('should equal occupiedWidth for row components', () => {
|
||||
expect(
|
||||
getDetailedComponentWidth({
|
||||
id: 'row',
|
||||
components: {
|
||||
row: {
|
||||
id: 'row',
|
||||
type: types.ROW_TYPE,
|
||||
children: ['child', 'child'],
|
||||
},
|
||||
child: { id: 'child', meta: { width: 3.5 } },
|
||||
},
|
||||
}),
|
||||
).toEqual({ width: 12, occupiedWidth: 7, minimumWidth: 7 });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getDropPosition, {
|
||||
DROP_TOP,
|
||||
DROP_RIGHT,
|
||||
DROP_BOTTOM,
|
||||
DROP_LEFT,
|
||||
} from '../../../../src/dashboard/util/getDropPosition';
|
||||
|
||||
import {
|
||||
CHART_TYPE,
|
||||
DASHBOARD_GRID_TYPE,
|
||||
DASHBOARD_ROOT_TYPE,
|
||||
HEADER_TYPE,
|
||||
ROW_TYPE,
|
||||
TAB_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
describe('getDropPosition', () => {
|
||||
// helper to easily configure test
|
||||
function getMocks({
|
||||
parentType,
|
||||
componentType,
|
||||
draggingType,
|
||||
depth = 1,
|
||||
hasChildren = false,
|
||||
orientation = 'row',
|
||||
clientOffset = { x: 0, y: 0 },
|
||||
boundingClientRect = {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
isDraggingOverShallow = true,
|
||||
}) {
|
||||
const monitorMock = {
|
||||
getItem: () => ({
|
||||
id: 'id',
|
||||
type: draggingType,
|
||||
}),
|
||||
getClientOffset: () => clientOffset,
|
||||
};
|
||||
|
||||
const ComponentMock = {
|
||||
props: {
|
||||
depth,
|
||||
parentComponent: {
|
||||
type: parentType,
|
||||
},
|
||||
component: {
|
||||
type: componentType,
|
||||
children: hasChildren ? [''] : [],
|
||||
},
|
||||
orientation,
|
||||
isDraggingOverShallow,
|
||||
},
|
||||
ref: {
|
||||
getBoundingClientRect: () => boundingClientRect,
|
||||
},
|
||||
};
|
||||
|
||||
return [monitorMock, ComponentMock];
|
||||
}
|
||||
|
||||
describe('invalid child + invalid sibling', () => {
|
||||
it('should return null', () => {
|
||||
const result = getDropPosition(
|
||||
// TAB is an invalid child + sibling of GRID > ROW
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: TAB_TYPE,
|
||||
}),
|
||||
);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('valid child + invalid sibling', () => {
|
||||
it('should return DROP_LEFT if component has NO children, and orientation is "row"', () => {
|
||||
// HEADER is a valid child + invalid sibling of ROOT > GRID
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_ROOT_TYPE,
|
||||
componentType: DASHBOARD_GRID_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_LEFT);
|
||||
});
|
||||
|
||||
it('should return DROP_RIGHT if component HAS children, and orientation is "row"', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_ROOT_TYPE,
|
||||
componentType: DASHBOARD_GRID_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
hasChildren: true,
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_RIGHT);
|
||||
});
|
||||
|
||||
it('should return DROP_TOP if component has NO children, and orientation is "column"', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_ROOT_TYPE,
|
||||
componentType: DASHBOARD_GRID_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
orientation: 'column',
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_TOP);
|
||||
});
|
||||
|
||||
it('should return DROP_BOTTOM if component HAS children, and orientation is "column"', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_ROOT_TYPE,
|
||||
componentType: DASHBOARD_GRID_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
orientation: 'column',
|
||||
hasChildren: true,
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_BOTTOM);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid child + valid sibling', () => {
|
||||
it('should return DROP_TOP if orientation="row" and clientOffset is closer to component top than bottom', () => {
|
||||
const result = getDropPosition(
|
||||
// HEADER is an invalid child but valid sibling of GRID > ROW
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
clientOffset: { y: 10 },
|
||||
boundingClientRect: {
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_TOP);
|
||||
});
|
||||
|
||||
it('should return DROP_BOTTOM if orientation="row" and clientOffset is closer to component bottom than top', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
clientOffset: { y: 55 },
|
||||
boundingClientRect: {
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_BOTTOM);
|
||||
});
|
||||
|
||||
it('should return DROP_LEFT if orientation="column" and clientOffset is closer to component left than right', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
orientation: 'column',
|
||||
clientOffset: { x: 45 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_LEFT);
|
||||
});
|
||||
|
||||
it('should return DROP_RIGHT if orientation="column" and clientOffset is closer to component right than left', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: HEADER_TYPE,
|
||||
orientation: 'column',
|
||||
clientOffset: { x: 55 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_RIGHT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('child + valid sibling (row orientation)', () => {
|
||||
it('should return DROP_LEFT if component has NO children, and clientOffset is NOT near top/bottom sibling boundary', () => {
|
||||
const result = getDropPosition(
|
||||
// CHART is a valid child + sibling of GRID > ROW
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
clientOffset: { x: 10, y: 50 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_LEFT);
|
||||
});
|
||||
|
||||
it('should return DROP_RIGHT if component HAS children, and clientOffset is NOT near top/bottom sibling boundary', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 10, y: 50 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_RIGHT);
|
||||
});
|
||||
|
||||
it('should return DROP_TOP regardless of component children if clientOffset IS near top sibling boundary', () => {
|
||||
const noChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
clientOffset: { x: 10, y: 2 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const withChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 10, y: 2 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(noChildren).toBe(DROP_TOP);
|
||||
expect(withChildren).toBe(DROP_TOP);
|
||||
});
|
||||
|
||||
it('should return DROP_BOTTOM regardless of component children if clientOffset IS near bottom sibling boundary', () => {
|
||||
const noChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
clientOffset: { x: 10, y: 95 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const withChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 10, y: 95 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(noChildren).toBe(DROP_BOTTOM);
|
||||
expect(withChildren).toBe(DROP_BOTTOM);
|
||||
});
|
||||
});
|
||||
|
||||
describe('child + valid sibling (column orientation)', () => {
|
||||
it('should return DROP_TOP if component has NO children, and clientOffset is NOT near left/right sibling boundary', () => {
|
||||
const result = getDropPosition(
|
||||
// CHART is a valid child + sibling of GRID > ROW
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
clientOffset: { x: 50, y: 0 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_TOP);
|
||||
});
|
||||
|
||||
it('should return DROP_BOTTOM if component HAS children, and clientOffset is NOT near left/right sibling boundary', () => {
|
||||
const result = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 50, y: 0 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).toBe(DROP_BOTTOM);
|
||||
});
|
||||
|
||||
it('should return DROP_LEFT regardless of component children if clientOffset IS near left sibling boundary', () => {
|
||||
const noChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
clientOffset: { x: 10, y: 2 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const withChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 10, y: 2 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(noChildren).toBe(DROP_LEFT);
|
||||
expect(withChildren).toBe(DROP_LEFT);
|
||||
});
|
||||
|
||||
it('should return DROP_RIGHT regardless of component children if clientOffset IS near right sibling boundary', () => {
|
||||
const noChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
clientOffset: { x: 90, y: 95 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const withChildren = getDropPosition(
|
||||
...getMocks({
|
||||
parentType: DASHBOARD_GRID_TYPE,
|
||||
componentType: ROW_TYPE,
|
||||
draggingType: CHART_TYPE,
|
||||
orientation: 'column',
|
||||
hasChildren: true,
|
||||
clientOffset: { x: 90, y: 95 },
|
||||
boundingClientRect: {
|
||||
left: 0,
|
||||
right: 100,
|
||||
top: 0,
|
||||
bottom: 100,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(noChildren).toBe(DROP_RIGHT);
|
||||
expect(withChildren).toBe(DROP_RIGHT);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getFilterConfigsFromFormdata from '../../../../src/dashboard/util/getFilterConfigsFromFormdata';
|
||||
|
||||
describe('getFilterConfigsFromFormdata', () => {
|
||||
const testFormdata = {
|
||||
filter_configs: [
|
||||
{
|
||||
asc: true,
|
||||
clearable: true,
|
||||
column: 'state',
|
||||
defaultValue: 'CA',
|
||||
key: 'fvwncPjUf',
|
||||
multiple: true,
|
||||
},
|
||||
],
|
||||
date_filter: true,
|
||||
granularity_sqla: '__time',
|
||||
time_grain_sqla: 'P1M',
|
||||
time_range: '2018-12-30T00:00:00+:+last+saturday',
|
||||
};
|
||||
|
||||
it('should add time grain', () => {
|
||||
const result = getFilterConfigsFromFormdata({
|
||||
...testFormdata,
|
||||
show_sqla_time_granularity: true,
|
||||
});
|
||||
expect(result.columns).toMatchObject({
|
||||
__time_grain: testFormdata.time_grain_sqla,
|
||||
});
|
||||
});
|
||||
|
||||
it('should add time column', () => {
|
||||
const result = getFilterConfigsFromFormdata({
|
||||
...testFormdata,
|
||||
show_sqla_time_column: true,
|
||||
});
|
||||
expect(result.columns).toMatchObject({
|
||||
__time_col: testFormdata.granularity_sqla,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use default value from form_data', () => {
|
||||
const result = getFilterConfigsFromFormdata({
|
||||
...testFormdata,
|
||||
show_sqla_time_column: true,
|
||||
});
|
||||
expect(result.columns).toMatchObject({
|
||||
state: ['CA'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should read multi values from form_data', () => {
|
||||
const result = getFilterConfigsFromFormdata({
|
||||
...testFormdata,
|
||||
filter_configs: [
|
||||
{
|
||||
asc: true,
|
||||
clearable: true,
|
||||
column: 'state',
|
||||
defaultValue: 'CA;NY',
|
||||
key: 'fvwncPjUf',
|
||||
multiple: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result.columns).toMatchObject({
|
||||
state: ['CA', 'NY'],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getFilterScopeFromNodesTree from '../../../../src/dashboard/util/getFilterScopeFromNodesTree';
|
||||
|
||||
describe('getFilterScopeFromNodesTree', () => {
|
||||
it('should return empty scope', () => {
|
||||
const nodes = [];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '107_region',
|
||||
nodes,
|
||||
checkedChartIds: [],
|
||||
}),
|
||||
).toEqual({});
|
||||
});
|
||||
|
||||
it('should return scope for simple grid', () => {
|
||||
const nodes = [
|
||||
{
|
||||
label: 'All dashboard',
|
||||
type: 'ROOT',
|
||||
value: 'ROOT_ID',
|
||||
children: [
|
||||
{
|
||||
value: 104,
|
||||
label: 'Life Expectancy VS Rural %',
|
||||
type: 'CHART',
|
||||
},
|
||||
{ value: 105, label: 'Rural Breakdown', type: 'CHART' },
|
||||
{
|
||||
value: 106,
|
||||
label: "World's Pop Growth",
|
||||
type: 'CHART',
|
||||
},
|
||||
{
|
||||
label: 'Time Filter',
|
||||
showCheckbox: false,
|
||||
type: 'CHART',
|
||||
value: 108,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const checkedChartIds = [104, 106];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '108___time_range',
|
||||
nodes,
|
||||
checkedChartIds,
|
||||
}),
|
||||
).toEqual({
|
||||
scope: ['ROOT_ID'],
|
||||
immune: [105],
|
||||
});
|
||||
});
|
||||
|
||||
describe('should return scope for tabbed dashboard', () => {
|
||||
const nodes = [
|
||||
{
|
||||
label: 'All dashboard',
|
||||
type: 'ROOT',
|
||||
value: 'ROOT_ID',
|
||||
children: [
|
||||
{
|
||||
label: 'Tab 1',
|
||||
type: 'TAB',
|
||||
value: 'TAB-Rb5aaqKWgG',
|
||||
children: [
|
||||
{
|
||||
label: 'Geo Filters',
|
||||
showCheckbox: false,
|
||||
type: 'CHART',
|
||||
value: 107,
|
||||
},
|
||||
{
|
||||
label: "World's Pop Growth",
|
||||
showCheckbox: true,
|
||||
type: 'CHART',
|
||||
value: 106,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tab 2',
|
||||
type: 'TAB',
|
||||
value: 'TAB-w5Fp904Rs',
|
||||
children: [
|
||||
{
|
||||
label: 'Time Filter',
|
||||
showCheckbox: true,
|
||||
type: 'CHART',
|
||||
value: 108,
|
||||
},
|
||||
{
|
||||
label: 'Life Expectancy VS Rural %',
|
||||
showCheckbox: true,
|
||||
type: 'CHART',
|
||||
value: 104,
|
||||
},
|
||||
{
|
||||
label: 'Row Tab 1',
|
||||
type: 'TAB',
|
||||
value: 'TAB-E4mJaZ-uQM',
|
||||
children: [
|
||||
{
|
||||
value: 105,
|
||||
label: 'Rural Breakdown',
|
||||
type: 'CHART',
|
||||
showCheckbox: true,
|
||||
},
|
||||
{
|
||||
value: 103,
|
||||
label: '% Rural',
|
||||
type: 'CHART',
|
||||
showCheckbox: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'TAB-rLYu-Cryu',
|
||||
label: 'New Tab',
|
||||
type: 'TAB',
|
||||
children: [
|
||||
{
|
||||
value: 102,
|
||||
label: 'Most Populated Countries',
|
||||
type: 'CHART',
|
||||
showCheckbox: true,
|
||||
},
|
||||
{
|
||||
value: 101,
|
||||
label: "World's Population",
|
||||
type: 'CHART',
|
||||
showCheckbox: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
it('root level tab scope', () => {
|
||||
const checkedChartIds = [106];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '107_region',
|
||||
nodes,
|
||||
checkedChartIds,
|
||||
}),
|
||||
).toEqual({
|
||||
scope: ['TAB-Rb5aaqKWgG'],
|
||||
immune: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('global scope', () => {
|
||||
const checkedChartIds = [106, 104, 101, 102, 103, 105];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '107_country_name',
|
||||
nodes,
|
||||
checkedChartIds,
|
||||
}),
|
||||
).toEqual({
|
||||
scope: ['ROOT_ID'],
|
||||
immune: [108],
|
||||
});
|
||||
});
|
||||
|
||||
it('row level tab scope', () => {
|
||||
const checkedChartIds = [103, 105];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '108___time_range',
|
||||
nodes,
|
||||
checkedChartIds,
|
||||
}),
|
||||
).toEqual({
|
||||
scope: ['TAB-E4mJaZ-uQM'],
|
||||
immune: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('mixed row level and root level scope', () => {
|
||||
const checkedChartIds = [103, 105, 106];
|
||||
expect(
|
||||
getFilterScopeFromNodesTree({
|
||||
filterKey: '107_region',
|
||||
nodes,
|
||||
checkedChartIds,
|
||||
}),
|
||||
).toEqual({
|
||||
scope: ['TAB-Rb5aaqKWgG', 'TAB-E4mJaZ-uQM'],
|
||||
immune: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getFormDataWithExtraFilters from '../../../../src/dashboard/util/charts/getFormDataWithExtraFilters';
|
||||
|
||||
describe('getFormDataWithExtraFilters', () => {
|
||||
const chartId = 'chartId';
|
||||
const mockArgs = {
|
||||
chart: {
|
||||
id: chartId,
|
||||
formData: {
|
||||
filters: [
|
||||
{
|
||||
col: 'country_name',
|
||||
op: 'in',
|
||||
val: ['United States'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
region: ['Spain'],
|
||||
color: ['pink', 'purple'],
|
||||
},
|
||||
sliceId: chartId,
|
||||
};
|
||||
|
||||
it('should include filters from the passed filters', () => {
|
||||
const result = getFormDataWithExtraFilters(mockArgs);
|
||||
expect(result.extra_filters).toHaveLength(2);
|
||||
expect(result.extra_filters[0]).toEqual({
|
||||
col: 'region',
|
||||
op: 'in',
|
||||
val: ['Spain'],
|
||||
});
|
||||
expect(result.extra_filters[1]).toEqual({
|
||||
col: 'color',
|
||||
op: 'in',
|
||||
val: ['pink', 'purple'],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getLeafComponentIdFromPath from '../../../../src/dashboard/util/getLeafComponentIdFromPath';
|
||||
import { filterId } from '../fixtures/mockSliceEntities';
|
||||
import { dashboardFilters } from '../fixtures/mockDashboardFilters';
|
||||
|
||||
describe('getLeafComponentIdFromPath', () => {
|
||||
const path = dashboardFilters[filterId].directPathToFilter;
|
||||
const leaf = path.slice().pop();
|
||||
|
||||
it('should return component id', () => {
|
||||
expect(getLeafComponentIdFromPath(path)).toBe(leaf);
|
||||
});
|
||||
|
||||
it('should not return label component', () => {
|
||||
const updatedPath = dashboardFilters[filterId].directPathToFilter.concat(
|
||||
'LABEL-test123',
|
||||
);
|
||||
expect(getLeafComponentIdFromPath(updatedPath)).toBe(leaf);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import isValidChild from '../../../../src/dashboard/util/isValidChild';
|
||||
|
||||
import {
|
||||
CHART_TYPE as CHART,
|
||||
COLUMN_TYPE as COLUMN,
|
||||
DASHBOARD_GRID_TYPE as GRID,
|
||||
DASHBOARD_ROOT_TYPE as ROOT,
|
||||
DIVIDER_TYPE as DIVIDER,
|
||||
HEADER_TYPE as HEADER,
|
||||
MARKDOWN_TYPE as MARKDOWN,
|
||||
ROW_TYPE as ROW,
|
||||
TABS_TYPE as TABS,
|
||||
TAB_TYPE as TAB,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
const getIndentation = depth =>
|
||||
Array(depth * 3)
|
||||
.fill('')
|
||||
.join('-');
|
||||
|
||||
describe('isValidChild', () => {
|
||||
describe('valid calls', () => {
|
||||
// these are representations of nested structures for easy testing
|
||||
// [ROOT (depth 0) > GRID (depth 1) > HEADER (depth 2)]
|
||||
// every unique parent > child relationship is tested, but because this
|
||||
// test representation WILL result in duplicates, we hash each test
|
||||
// to keep track of which we've run
|
||||
const didTest = {};
|
||||
const validExamples = [
|
||||
[ROOT, GRID, CHART], // chart is valid because it is wrapped in a row
|
||||
[ROOT, GRID, MARKDOWN], // markdown is valid because it is wrapped in a row
|
||||
[ROOT, GRID, COLUMN], // column is valid because it is wrapped in a row
|
||||
[ROOT, GRID, HEADER],
|
||||
[ROOT, GRID, ROW, MARKDOWN],
|
||||
[ROOT, GRID, ROW, CHART],
|
||||
|
||||
[ROOT, GRID, ROW, COLUMN, HEADER],
|
||||
[ROOT, GRID, ROW, COLUMN, DIVIDER],
|
||||
[ROOT, GRID, ROW, COLUMN, CHART],
|
||||
[ROOT, GRID, ROW, COLUMN, MARKDOWN],
|
||||
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, CHART],
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, MARKDOWN],
|
||||
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, COLUMN, CHART],
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, COLUMN, MARKDOWN],
|
||||
[ROOT, GRID, TABS, TAB, ROW, COLUMN, ROW, COLUMN, MARKDOWN],
|
||||
|
||||
// tab equivalents
|
||||
[ROOT, TABS, TAB, CHART],
|
||||
[ROOT, TABS, TAB, MARKDOWN],
|
||||
[ROOT, TABS, TAB, COLUMN],
|
||||
[ROOT, TABS, TAB, HEADER],
|
||||
[ROOT, TABS, TAB, ROW, MARKDOWN],
|
||||
[ROOT, TABS, TAB, ROW, CHART],
|
||||
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, HEADER],
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, DIVIDER],
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, CHART],
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, MARKDOWN],
|
||||
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, ROW, CHART],
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, ROW, MARKDOWN],
|
||||
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, ROW, COLUMN, CHART],
|
||||
[ROOT, TABS, TAB, ROW, COLUMN, ROW, COLUMN, MARKDOWN],
|
||||
[ROOT, TABS, TAB, TABS, TAB, ROW, COLUMN, ROW, COLUMN, MARKDOWN],
|
||||
];
|
||||
|
||||
validExamples.forEach((example, exampleIdx) => {
|
||||
let childDepth = 0;
|
||||
example.forEach((childType, i) => {
|
||||
const parentDepth = childDepth - 1;
|
||||
const parentType = example[i - 1];
|
||||
const testKey = `${parentType}-${childType}-${parentDepth}`;
|
||||
|
||||
if (i > 0 && !didTest[testKey]) {
|
||||
didTest[testKey] = true;
|
||||
|
||||
it(`(${exampleIdx})${getIndentation(
|
||||
childDepth,
|
||||
)}${parentType} (depth ${parentDepth}) > ${childType} ✅`, () => {
|
||||
expect(
|
||||
isValidChild({
|
||||
parentDepth,
|
||||
parentType,
|
||||
childType,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
}
|
||||
// see isValidChild.js for why tabs do not increment the depth of their children
|
||||
childDepth += childType !== TABS && childType !== TAB ? 1 : 0;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid calls', () => {
|
||||
// In order to assert that a parent > child hierarchy at a given depth is invalid
|
||||
// we also define some valid hierarchies in doing so. we indicate which
|
||||
// parent > [child] relationships should be asserted as invalid using a nested array
|
||||
const invalidExamples = [
|
||||
[ROOT, [DIVIDER]],
|
||||
[ROOT, [CHART]],
|
||||
[ROOT, [MARKDOWN]],
|
||||
[ROOT, GRID, [TAB]],
|
||||
[ROOT, GRID, TABS, [ROW]],
|
||||
// [ROOT, GRID, TABS, TAB, [TABS]], // @TODO this needs to be fixed
|
||||
[ROOT, GRID, ROW, [TABS]],
|
||||
[ROOT, GRID, ROW, [TAB]],
|
||||
[ROOT, GRID, ROW, [DIVIDER]],
|
||||
[ROOT, GRID, ROW, COLUMN, [TABS]],
|
||||
[ROOT, GRID, ROW, COLUMN, [TAB]],
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, [DIVIDER]],
|
||||
[ROOT, GRID, ROW, COLUMN, ROW, COLUMN, [ROW]], // too nested
|
||||
];
|
||||
|
||||
invalidExamples.forEach((example, exampleIdx) => {
|
||||
let childDepth = 0;
|
||||
example.forEach((childType, i) => {
|
||||
const shouldTestChild = Array.isArray(childType);
|
||||
|
||||
if (i > 0 && shouldTestChild) {
|
||||
const parentDepth = childDepth - 1;
|
||||
const parentType = example[i - 1];
|
||||
|
||||
it(`(${exampleIdx})${getIndentation(
|
||||
childDepth,
|
||||
)}${parentType} (depth ${parentDepth}) > ${childType} ❌`, () => {
|
||||
expect(
|
||||
isValidChild({
|
||||
parentDepth,
|
||||
parentType,
|
||||
childType,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
}
|
||||
// see isValidChild.js for why tabs do not increment the depth of their children
|
||||
childDepth += childType !== TABS && childType !== TAB ? 1 : 0;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import newComponentFactory from '../../../../src/dashboard/util/newComponentFactory';
|
||||
|
||||
import {
|
||||
CHART_TYPE,
|
||||
COLUMN_TYPE,
|
||||
DASHBOARD_GRID_TYPE,
|
||||
DASHBOARD_ROOT_TYPE,
|
||||
DIVIDER_TYPE,
|
||||
HEADER_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
NEW_COMPONENT_SOURCE_TYPE,
|
||||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
const types = [
|
||||
CHART_TYPE,
|
||||
COLUMN_TYPE,
|
||||
DASHBOARD_GRID_TYPE,
|
||||
DASHBOARD_ROOT_TYPE,
|
||||
DIVIDER_TYPE,
|
||||
HEADER_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
NEW_COMPONENT_SOURCE_TYPE,
|
||||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
];
|
||||
|
||||
describe('newEntityFactory', () => {
|
||||
types.forEach(type => {
|
||||
it(`returns a new ${type}`, () => {
|
||||
const result = newComponentFactory(type);
|
||||
|
||||
expect(result.type).toBe(type);
|
||||
expect(typeof result.id).toBe('string');
|
||||
expect(typeof result.meta).toBe('object');
|
||||
expect(Array.isArray(result.children)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds passed meta data to the entity', () => {
|
||||
const banana = 'banana';
|
||||
const result = newComponentFactory(CHART_TYPE, { banana });
|
||||
expect(result.meta.banana).toBe(banana);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import newEntitiesFromDrop from '../../../../src/dashboard/util/newEntitiesFromDrop';
|
||||
import {
|
||||
CHART_TYPE,
|
||||
DASHBOARD_GRID_TYPE,
|
||||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
} from '../../../../src/dashboard/util/componentTypes';
|
||||
|
||||
describe('newEntitiesFromDrop', () => {
|
||||
it('should return a new Entity of appropriate type, and add it to the drop target children', () => {
|
||||
const result = newEntitiesFromDrop({
|
||||
dropResult: {
|
||||
destination: { id: 'a', index: 0 },
|
||||
dragging: { type: CHART_TYPE },
|
||||
source: { id: 'b', index: 0 },
|
||||
},
|
||||
layout: {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: ROW_TYPE,
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newId = result.a.children[0];
|
||||
expect(result.a.children).toHaveLength(1);
|
||||
expect(Object.keys(result)).toHaveLength(2);
|
||||
expect(result[newId].type).toBe(CHART_TYPE);
|
||||
});
|
||||
|
||||
it('should create Tab AND Tabs components if the drag entity is Tabs', () => {
|
||||
const result = newEntitiesFromDrop({
|
||||
dropResult: {
|
||||
destination: { id: 'a', index: 0 },
|
||||
dragging: { type: TABS_TYPE },
|
||||
source: { id: 'b', index: 0 },
|
||||
},
|
||||
layout: {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: DASHBOARD_GRID_TYPE,
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newTabsId = result.a.children[0];
|
||||
const newTabId = result[newTabsId].children[0];
|
||||
|
||||
expect(result.a.children).toHaveLength(1);
|
||||
expect(Object.keys(result)).toHaveLength(3);
|
||||
expect(result[newTabsId].type).toBe(TABS_TYPE);
|
||||
expect(result[newTabId].type).toBe(TAB_TYPE);
|
||||
});
|
||||
|
||||
it('should create a Row if the drag entity should be wrapped in a row', () => {
|
||||
const result = newEntitiesFromDrop({
|
||||
dropResult: {
|
||||
destination: { id: 'a', index: 0 },
|
||||
dragging: { type: CHART_TYPE },
|
||||
source: { id: 'b', index: 0 },
|
||||
},
|
||||
layout: {
|
||||
a: {
|
||||
id: 'a',
|
||||
type: DASHBOARD_GRID_TYPE,
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newRowId = result.a.children[0];
|
||||
const newChartId = result[newRowId].children[0];
|
||||
|
||||
expect(result.a.children).toHaveLength(1);
|
||||
expect(Object.keys(result)).toHaveLength(3);
|
||||
expect(result[newRowId].type).toBe(ROW_TYPE);
|
||||
expect(result[newChartId].type).toBe(CHART_TYPE);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* 'License'); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import updateComponentParentsList from '../../../../src/dashboard/util/updateComponentParentsList';
|
||||
import { DASHBOARD_ROOT_ID } from '../../../../src/dashboard/util/constants';
|
||||
import {
|
||||
dashboardLayout,
|
||||
dashboardLayoutWithTabs,
|
||||
} from '../fixtures/mockDashboardLayout';
|
||||
|
||||
describe('updateComponentParentsList', () => {
|
||||
const emptyLayout = {
|
||||
DASHBOARD_VERSION_KEY: 'v2',
|
||||
GRID_ID: {
|
||||
children: [],
|
||||
id: 'GRID_ID',
|
||||
type: 'GRID',
|
||||
},
|
||||
ROOT_ID: {
|
||||
children: ['GRID_ID'],
|
||||
id: 'ROOT_ID',
|
||||
type: 'ROOT',
|
||||
},
|
||||
};
|
||||
const gridLayout = {
|
||||
...dashboardLayout.present,
|
||||
};
|
||||
const tabsLayout = {
|
||||
...dashboardLayoutWithTabs.present,
|
||||
};
|
||||
|
||||
it('should handle empty layout', () => {
|
||||
const nextState = {
|
||||
...emptyLayout,
|
||||
};
|
||||
|
||||
updateComponentParentsList({
|
||||
currentComponent: nextState[DASHBOARD_ROOT_ID],
|
||||
layout: nextState,
|
||||
});
|
||||
|
||||
expect(nextState.GRID_ID.parents).toEqual(['ROOT_ID']);
|
||||
});
|
||||
|
||||
it('should handle grid layout', () => {
|
||||
const nextState = {
|
||||
...gridLayout,
|
||||
};
|
||||
|
||||
updateComponentParentsList({
|
||||
currentComponent: nextState[DASHBOARD_ROOT_ID],
|
||||
layout: nextState,
|
||||
});
|
||||
|
||||
expect(nextState.GRID_ID.parents).toEqual(['ROOT_ID']);
|
||||
expect(nextState.CHART_ID.parents).toEqual([
|
||||
'ROOT_ID',
|
||||
'GRID_ID',
|
||||
'ROW_ID',
|
||||
'COLUMN_ID',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle root level tabs', () => {
|
||||
const nextState = {
|
||||
...tabsLayout,
|
||||
};
|
||||
|
||||
updateComponentParentsList({
|
||||
currentComponent: nextState[DASHBOARD_ROOT_ID],
|
||||
layout: nextState,
|
||||
});
|
||||
|
||||
expect(nextState.GRID_ID.parents).toEqual(['ROOT_ID']);
|
||||
expect(nextState.CHART_ID2.parents).toEqual([
|
||||
'ROOT_ID',
|
||||
'TABS_ID',
|
||||
'TAB_ID2',
|
||||
'ROW_ID2',
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user