mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-24 09:50:01 +00:00
UI :- Added functionality to drag and drop teams in another team (#9152)
* Added functionality to drag and drop teams in another team * remove immutability package * changes as per comments * Added unit test * changes as per comments * minor changes * added expandable config * changes as per comments * changes as per comments Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com>
This commit is contained in:
parent
775016488d
commit
2303aede92
@ -74,6 +74,8 @@
|
||||
"react-codemirror2": "^7.2.1",
|
||||
"react-context-mutex": "^2.0.0",
|
||||
"react-copy-to-clipboard": "^5.0.4",
|
||||
"react-dnd": "14.0.2",
|
||||
"react-dnd-html5-backend": "14.0.2",
|
||||
"react-dom": "^16.14.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-i18next": "^11.18.6",
|
||||
@ -181,6 +183,7 @@
|
||||
"connect-api-mocker": "^1.10.0",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"css-loader": "^6.7.2",
|
||||
"cypress-postgresql": "^1.0.8",
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
@ -219,7 +222,6 @@
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-cli": "^4.3.1",
|
||||
"webpack-dev-server": "^4.11.1",
|
||||
"webpackbar": "^5.0.0-3",
|
||||
"cypress-postgresql": "^1.0.8"
|
||||
"webpackbar": "^5.0.0-3"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.83464 11.3334C1.51241 11.3334 1.23741 11.2195 1.00964 10.9917C0.781858 10.764 0.667969 10.489 0.667969 10.1667C0.667969 9.84453 0.781858 9.56953 1.00964 9.34175C1.23741 9.11397 1.51241 9.00008 1.83464 9.00008C2.15686 9.00008 2.43186 9.11397 2.65964 9.34175C2.88741 9.56953 3.0013 9.84453 3.0013 10.1667C3.0013 10.489 2.88741 10.764 2.65964 10.9917C2.43186 11.2195 2.15686 11.3334 1.83464 11.3334ZM6.16797 11.3334C5.84575 11.3334 5.57075 11.2195 5.34297 10.9917C5.11519 10.764 5.0013 10.489 5.0013 10.1667C5.0013 9.84453 5.11519 9.56953 5.34297 9.34175C5.57075 9.11397 5.84575 9.00008 6.16797 9.00008C6.49019 9.00008 6.76519 9.11397 6.99297 9.34175C7.22075 9.56953 7.33463 9.84453 7.33463 10.1667C7.33463 10.489 7.22075 10.764 6.99297 10.9917C6.76519 11.2195 6.49019 11.3334 6.16797 11.3334ZM1.83464 7.16675C1.51241 7.16675 1.23741 7.05286 1.00964 6.82508C0.781858 6.5973 0.667969 6.3223 0.667969 6.00008C0.667969 5.67786 0.781858 5.40286 1.00964 5.17508C1.23741 4.9473 1.51241 4.83342 1.83464 4.83342C2.15686 4.83342 2.43186 4.9473 2.65964 5.17508C2.88741 5.40286 3.0013 5.67786 3.0013 6.00008C3.0013 6.3223 2.88741 6.5973 2.65964 6.82508C2.43186 7.05286 2.15686 7.16675 1.83464 7.16675ZM6.16797 7.16675C5.84575 7.16675 5.57075 7.05286 5.34297 6.82508C5.11519 6.5973 5.0013 6.3223 5.0013 6.00008C5.0013 5.67786 5.11519 5.40286 5.34297 5.17508C5.57075 4.9473 5.84575 4.83342 6.16797 4.83342C6.49019 4.83342 6.76519 4.9473 6.99297 5.17508C7.22075 5.40286 7.33463 5.67786 7.33463 6.00008C7.33463 6.3223 7.22075 6.5973 6.99297 6.82508C6.76519 7.05286 6.49019 7.16675 6.16797 7.16675ZM1.83464 3.00008C1.51241 3.00008 1.23741 2.88619 1.00964 2.65841C0.781858 2.43064 0.667969 2.15564 0.667969 1.83341C0.667969 1.51119 0.781858 1.23619 1.00964 1.00841C1.23741 0.780637 1.51241 0.666748 1.83464 0.666748C2.15686 0.666748 2.43186 0.780637 2.65964 1.00841C2.88741 1.23619 3.0013 1.51119 3.0013 1.83341C3.0013 2.15564 2.88741 2.43064 2.65964 2.65841C2.43186 2.88619 2.15686 3.00008 1.83464 3.00008ZM6.16797 3.00008C5.84575 3.00008 5.57075 2.88619 5.34297 2.65841C5.11519 2.43064 5.0013 2.15564 5.0013 1.83341C5.0013 1.51119 5.11519 1.23619 5.34297 1.00841C5.57075 0.780637 5.84575 0.666748 6.16797 0.666748C6.49019 0.666748 6.76519 0.780637 6.99297 1.00841C7.22075 1.23619 7.33463 1.51119 7.33463 1.83341C7.33463 2.15564 7.22075 2.43064 6.99297 2.65841C6.76519 2.88619 6.49019 3.00008 6.16797 3.00008Z" fill="#76746F"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
@ -13,7 +13,7 @@
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { RestoreEntitiesRequestType } from 'Models';
|
||||
import { RestoreRequestType } from 'Models';
|
||||
import { Dashboard } from '../generated/entity/data/dashboard';
|
||||
import { EntityHistory } from '../generated/type/entityHistory';
|
||||
import { EntityReference } from '../generated/type/entityReference';
|
||||
@ -122,7 +122,7 @@ export const patchDashboardDetails = async (id: string, data: Operation[]) => {
|
||||
|
||||
export const restoreDashboard = async (id: string) => {
|
||||
const response = await APIClient.put<
|
||||
RestoreEntitiesRequestType,
|
||||
RestoreRequestType,
|
||||
AxiosResponse<Dashboard>
|
||||
>('/dashboards/restore', { id });
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { PagingResponse, RestoreEntitiesRequestType } from 'Models';
|
||||
import { PagingResponse, RestoreRequestType } from 'Models';
|
||||
import { Pipeline, PipelineStatus } from '../generated/entity/data/pipeline';
|
||||
import { EntityHistory } from '../generated/type/entityHistory';
|
||||
import { EntityReference } from '../generated/type/entityReference';
|
||||
@ -140,7 +140,7 @@ export const getPipelineStatus = async (
|
||||
|
||||
export const restorePipeline = async (id: string) => {
|
||||
const response = await APIClient.put<
|
||||
RestoreEntitiesRequestType,
|
||||
RestoreRequestType,
|
||||
AxiosResponse<Pipeline>
|
||||
>('/pipelines/restore', {
|
||||
id,
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { RestoreEntitiesRequestType } from 'Models';
|
||||
import { RestoreRequestType } from 'Models';
|
||||
import {
|
||||
ColumnProfile,
|
||||
Table,
|
||||
@ -98,7 +98,7 @@ export const patchTableDetails = async (id: string, data: Operation[]) => {
|
||||
|
||||
export const restoreTable = async (id: string) => {
|
||||
const response = await APIClient.put<
|
||||
RestoreEntitiesRequestType,
|
||||
RestoreRequestType,
|
||||
AxiosResponse<Table>
|
||||
>('/tables/restore', { id });
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { isString } from 'lodash';
|
||||
import { RestoreRequestType } from 'Models';
|
||||
import { CreateTeam } from '../generated/api/teams/createTeam';
|
||||
import { Team } from '../generated/entity/teams/team';
|
||||
import { TeamHierarchy } from '../generated/entity/teams/teamHierarchy';
|
||||
@ -102,7 +103,7 @@ export const deleteTeam = async (id: string) => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const reactivateTeam = async (data: CreateTeam) => {
|
||||
export const updateTeam = async (data: CreateTeam) => {
|
||||
const response = await APIClient.put<CreateTeam, AxiosResponse<Team>>(
|
||||
'/teams',
|
||||
data
|
||||
@ -110,3 +111,12 @@ export const reactivateTeam = async (data: CreateTeam) => {
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const restoreTeam = async (id: string) => {
|
||||
const response = await APIClient.put<RestoreRequestType, AxiosResponse<Team>>(
|
||||
'/teams/restore',
|
||||
{ id }
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { RestoreEntitiesRequestType } from 'Models';
|
||||
import { RestoreRequestType } from 'Models';
|
||||
import { TabSpecificField } from '../enums/entity.enum';
|
||||
import { Topic } from '../generated/entity/data/topic';
|
||||
import { EntityHistory } from '../generated/type/entityHistory';
|
||||
@ -128,7 +128,7 @@ export const patchTopicDetails = async (id: string, data: Operation[]) => {
|
||||
|
||||
export const restoreTopic = async (id: string) => {
|
||||
const response = await APIClient.put<
|
||||
RestoreEntitiesRequestType,
|
||||
RestoreRequestType,
|
||||
AxiosResponse<Topic>
|
||||
>('/topics/restore', { id });
|
||||
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed 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 React, { useRef } from 'react';
|
||||
import { useDrag, useDrop } from 'react-dnd';
|
||||
import { DRAGGABLE_BODY_ROW } from '../../constants/Teams.constants';
|
||||
import { Team } from '../../generated/entity/teams/team';
|
||||
import { DragCollectProps, DraggableBodyRowProps } from './team.interface';
|
||||
|
||||
const DraggableBodyRow = ({
|
||||
index,
|
||||
handleMoveRow,
|
||||
className,
|
||||
record,
|
||||
style,
|
||||
...restProps
|
||||
}: DraggableBodyRowProps) => {
|
||||
const ref = useRef<HTMLTableRowElement>(null);
|
||||
const [{ isOver, dropClassName }, drop] = useDrop({
|
||||
accept: DRAGGABLE_BODY_ROW,
|
||||
collect: (monitor: DragCollectProps) => {
|
||||
const { index: dragIndex } = monitor?.getItem() || {};
|
||||
if (dragIndex === index) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
isOver: monitor.isOver(),
|
||||
dropClassName:
|
||||
dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
|
||||
};
|
||||
},
|
||||
// this will going to return the drag and drop object of a table
|
||||
drop: ({ record: dragRecord }: { record: Team }) => {
|
||||
handleMoveRow(dragRecord, record);
|
||||
},
|
||||
});
|
||||
// here we are passing the drag record
|
||||
const [, drag] = useDrag({
|
||||
type: DRAGGABLE_BODY_ROW,
|
||||
item: { record },
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
});
|
||||
drop(drag(ref));
|
||||
|
||||
return (
|
||||
<tr
|
||||
className={`${className}${isOver ? dropClassName : ''}`}
|
||||
ref={ref}
|
||||
style={{ cursor: 'move', ...style }}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DraggableBodyRow;
|
@ -36,7 +36,7 @@ import React, { Fragment, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AppState from '../../AppState';
|
||||
import { reactivateTeam } from '../../axiosAPIs/teamsAPI';
|
||||
import { restoreTeam } from '../../axiosAPIs/teamsAPI';
|
||||
import {
|
||||
getTeamAndUserDetailsPath,
|
||||
getUserPath,
|
||||
@ -76,7 +76,6 @@ import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import {
|
||||
filterChildTeams,
|
||||
getDeleteMessagePostFix,
|
||||
getRestoreTeamData,
|
||||
} from '../../utils/TeamUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
@ -514,9 +513,7 @@ const TeamDetailsV1 = ({
|
||||
|
||||
const handleReactiveTeam = async () => {
|
||||
try {
|
||||
const res = await reactivateTeam(
|
||||
getRestoreTeamData(currentTeam, childTeams)
|
||||
);
|
||||
const res = await restoreTeam(currentTeam.id);
|
||||
if (res) {
|
||||
afterDeleteAction();
|
||||
showSuccessToast(
|
||||
@ -1166,7 +1163,7 @@ const TeamDetailsV1 = ({
|
||||
) : (
|
||||
<Row
|
||||
className="team-list-container"
|
||||
gutter={[8, 8]}
|
||||
gutter={[8, 16]}
|
||||
justify="space-between">
|
||||
<Col span={8}>
|
||||
<Searchbar
|
||||
@ -1195,6 +1192,7 @@ const TeamDetailsV1 = ({
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<TeamHierarchy
|
||||
currentTeam={currentTeam}
|
||||
data={table as Team[]}
|
||||
onTeamExpand={onTeamExpand}
|
||||
/>
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed 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 { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MOCK_CURRENT_TEAM, MOCK_TABLE_DATA } from '../../mocks/Teams.mock';
|
||||
import { TeamHierarchyProps } from './team.interface';
|
||||
import TeamHierarchy from './TeamHierarchy';
|
||||
|
||||
const teamHierarchyPropsData: TeamHierarchyProps = {
|
||||
data: MOCK_TABLE_DATA,
|
||||
currentTeam: MOCK_CURRENT_TEAM,
|
||||
onTeamExpand: jest.fn(),
|
||||
};
|
||||
|
||||
const mockShowErrorToast = jest.fn();
|
||||
|
||||
// mock library imports
|
||||
jest.mock('react-router-dom', () => ({
|
||||
Link: jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }) => <a href="#">{children}</a>),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/TeamUtils', () => ({
|
||||
getMovedTeamData: jest.fn().mockReturnValue([]),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/teamsAPI', () => ({
|
||||
updateTeam: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(MOCK_CURRENT_TEAM)),
|
||||
getTeamByName: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(MOCK_CURRENT_TEAM)),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/CommonUtils', () => ({
|
||||
getEntityName: jest.fn().mockReturnValue('entityName'),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/RouterUtils', () => ({
|
||||
getTeamsWithFqnPath: jest.fn().mockReturnValue([]),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/ToastUtils', () => ({
|
||||
showErrorToast: jest.fn().mockImplementation(() => mockShowErrorToast),
|
||||
}));
|
||||
|
||||
describe('Team Hierarchy page', () => {
|
||||
it('Initially, Table should load', async () => {
|
||||
await act(async () => {
|
||||
render(<TeamHierarchy {...teamHierarchyPropsData} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const table = await screen.findByTestId('team-hierarchy-table');
|
||||
|
||||
expect(table).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render all table columns', async () => {
|
||||
await act(async () => {
|
||||
render(<TeamHierarchy {...teamHierarchyPropsData} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const table = await screen.findByTestId('team-hierarchy-table');
|
||||
const teamsColumn = await screen.findByText('Teams');
|
||||
const typeColumn = await screen.findByText('Type');
|
||||
const subTeamsColumn = await screen.findByText('Sub Teams');
|
||||
const usersColumn = await screen.findByText('Users');
|
||||
const assetCountColumn = await screen.findByText('Asset Count');
|
||||
const descriptionColumn = await screen.findByText('Description');
|
||||
const rows = await screen.findAllByRole('row');
|
||||
|
||||
expect(table).toBeInTheDocument();
|
||||
expect(teamsColumn).toBeInTheDocument();
|
||||
expect(typeColumn).toBeInTheDocument();
|
||||
expect(subTeamsColumn).toBeInTheDocument();
|
||||
expect(usersColumn).toBeInTheDocument();
|
||||
expect(assetCountColumn).toBeInTheDocument();
|
||||
expect(descriptionColumn).toBeInTheDocument();
|
||||
|
||||
expect(rows).toHaveLength(MOCK_TABLE_DATA.length + 1);
|
||||
});
|
||||
|
||||
it('Should render child row in table', async () => {
|
||||
await act(async () => {
|
||||
render(<TeamHierarchy {...teamHierarchyPropsData} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const table = await screen.findByTestId('team-hierarchy-table');
|
||||
|
||||
expect(table).toBeInTheDocument();
|
||||
|
||||
const expandableTableRow = await screen.getAllByTestId('expand-table-row');
|
||||
fireEvent.click(expandableTableRow[0]);
|
||||
|
||||
const totalRows = await screen.findAllByText('entityName');
|
||||
|
||||
expect(totalRows).toHaveLength(5);
|
||||
});
|
||||
});
|
@ -11,27 +11,42 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Table } from 'antd';
|
||||
import { Modal, Table, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { isEmpty } from 'lodash';
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { ExpandableConfig } from 'antd/lib/table/interface';
|
||||
import { AxiosError } from 'axios';
|
||||
import { isArray, isEmpty } from 'lodash';
|
||||
import React, { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getTeamByName, updateTeam } from '../../axiosAPIs/teamsAPI';
|
||||
import { TABLE_CONSTANTS } from '../../constants/Teams.constants';
|
||||
import { Team } from '../../generated/entity/teams/team';
|
||||
import { getEntityName } from '../../utils/CommonUtils';
|
||||
import { getTeamsWithFqnPath } from '../../utils/RouterUtils';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import { getMovedTeamData } from '../../utils/TeamUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
|
||||
import {
|
||||
DraggableBodyRowProps,
|
||||
MovedTeamProps,
|
||||
TableExpandableDataProps,
|
||||
TeamHierarchyProps,
|
||||
} from './team.interface';
|
||||
import './teams.less';
|
||||
|
||||
interface TeamHierarchyProps {
|
||||
data: Team[];
|
||||
onTeamExpand: (
|
||||
loading?: boolean,
|
||||
parentTeam?: string,
|
||||
updateChildNode?: boolean
|
||||
) => void;
|
||||
}
|
||||
const TeamHierarchy: FC<TeamHierarchyProps> = ({
|
||||
currentTeam,
|
||||
data,
|
||||
onTeamExpand,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const [isTableLoading, setIsTableLoading] = useState<boolean>(false);
|
||||
const [movedTeam, setMovedTeam] = useState<MovedTeamProps>();
|
||||
|
||||
const TeamHierarchy: FC<TeamHierarchyProps> = ({ data, onTeamExpand }) => {
|
||||
const columns: ColumnsType<Team> = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
@ -78,42 +93,137 @@ const TeamHierarchy: FC<TeamHierarchyProps> = ({ data, onTeamExpand }) => {
|
||||
];
|
||||
}, [data, onTeamExpand]);
|
||||
|
||||
return (
|
||||
<Table
|
||||
bordered
|
||||
className="teams-list-table"
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
expandable={{
|
||||
expandIcon: ({ expanded, onExpand, expandable, record }) =>
|
||||
expandable ? (
|
||||
<span
|
||||
className="m-r-xs cursor-pointer"
|
||||
onClick={(e) =>
|
||||
onExpand(
|
||||
record,
|
||||
e as unknown as React.MouseEvent<HTMLElement, MouseEvent>
|
||||
)
|
||||
}>
|
||||
<SVGIcons
|
||||
icon={
|
||||
expanded ? Icons.ARROW_DOWN_LIGHT : Icons.ARROW_RIGHT_LIGHT
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<div className="expand-cell-icon-container" />
|
||||
),
|
||||
}}
|
||||
pagination={false}
|
||||
rowKey="name"
|
||||
size="small"
|
||||
onExpand={(isOpen, record) => {
|
||||
const handleMoveRow = useCallback(
|
||||
async (dragRecord: Team, dropRecord: Team) => {
|
||||
if (dragRecord.id === dropRecord.id) {
|
||||
return;
|
||||
}
|
||||
let dropTeam: Team = dropRecord;
|
||||
if (!isArray(dropTeam.children)) {
|
||||
const res = await getTeamByName(dropTeam.name, ['parents'], 'all');
|
||||
dropTeam = (res.parents?.[0] as Team) || currentTeam;
|
||||
}
|
||||
setMovedTeam({
|
||||
from: dragRecord,
|
||||
to: dropTeam,
|
||||
});
|
||||
setIsModalOpen(true);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleChangeTeam = async () => {
|
||||
if (movedTeam) {
|
||||
setIsTableLoading(true);
|
||||
try {
|
||||
const data = await getTeamByName(
|
||||
movedTeam.from.name,
|
||||
['users', 'defaultRoles', 'policies', 'owner', 'parents', 'children'],
|
||||
'all'
|
||||
);
|
||||
await updateTeam(getMovedTeamData(data, [movedTeam.to.id]));
|
||||
onTeamExpand(true, currentTeam?.name);
|
||||
showSuccessToast(t('message.team-moved-success'));
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError, t('server.team-moved-error'));
|
||||
} finally {
|
||||
setIsTableLoading(false);
|
||||
setIsModalOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tableExpandableIconData = useMemo(
|
||||
() =>
|
||||
({ expanded, onExpand, expandable, record }: TableExpandableDataProps) =>
|
||||
expandable ? (
|
||||
<div
|
||||
draggable
|
||||
className="expand-cell-icon-container"
|
||||
data-testid="expand-table-row"
|
||||
onClick={(e) =>
|
||||
onExpand(
|
||||
record,
|
||||
e as unknown as React.MouseEvent<HTMLElement, MouseEvent>
|
||||
)
|
||||
}>
|
||||
<SVGIcons
|
||||
className="drag-icon"
|
||||
draggable="true"
|
||||
icon={Icons.DRAG}
|
||||
/>
|
||||
<SVGIcons
|
||||
className="expand-icon"
|
||||
icon={expanded ? Icons.ARROW_DOWN_LIGHT : Icons.ARROW_RIGHT_LIGHT}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<SVGIcons className="drag-icon" icon={Icons.DRAG} />
|
||||
<div className="expand-cell-empty-icon-container" />
|
||||
</>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const expandableConfig: ExpandableConfig<Team> = useMemo(
|
||||
() => ({
|
||||
onExpand: (isOpen, record) => {
|
||||
if (isOpen && isEmpty(record.children)) {
|
||||
onTeamExpand(false, record.fullyQualifiedName, true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
},
|
||||
expandIcon: ({ expanded, onExpand, expandable, record }) =>
|
||||
tableExpandableIconData({ expanded, onExpand, expandable, record }),
|
||||
}),
|
||||
[onTeamExpand, tableExpandableIconData]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Table
|
||||
bordered
|
||||
className="teams-list-table"
|
||||
columns={columns}
|
||||
components={TABLE_CONSTANTS}
|
||||
data-testid="team-hierarchy-table"
|
||||
dataSource={data}
|
||||
expandable={expandableConfig}
|
||||
loading={isTableLoading}
|
||||
pagination={false}
|
||||
rowKey="name"
|
||||
size="small"
|
||||
onRow={(record, index) => {
|
||||
const attr = {
|
||||
index,
|
||||
handleMoveRow,
|
||||
record,
|
||||
};
|
||||
|
||||
return attr as DraggableBodyRowProps;
|
||||
}}
|
||||
/>
|
||||
</DndProvider>
|
||||
|
||||
<Modal
|
||||
centered
|
||||
destroyOnClose
|
||||
closable={false}
|
||||
data-testid="confirmation-modal"
|
||||
okText={t('label.confirm')}
|
||||
title={t('label.move-the-team')}
|
||||
visible={isModalOpen}
|
||||
onCancel={() => setIsModalOpen(false)}
|
||||
onOk={handleChangeTeam}>
|
||||
<Typography.Text>
|
||||
{t('message.team-transfer-message', {
|
||||
from: movedTeam?.from?.name,
|
||||
to: movedTeam?.to?.name,
|
||||
})}
|
||||
</Typography.Text>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed 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 { Team } from '../../generated/entity/teams/team';
|
||||
|
||||
export interface TeamHierarchyProps {
|
||||
currentTeam?: Team;
|
||||
data: Team[];
|
||||
onTeamExpand: (
|
||||
loading?: boolean,
|
||||
parentTeam?: string,
|
||||
updateChildNode?: boolean
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface DraggableBodyRowProps
|
||||
extends React.HTMLAttributes<HTMLTableRowElement> {
|
||||
index: number;
|
||||
handleMoveRow: (dragRecord: Team, dropRecord: Team) => void;
|
||||
record: Team;
|
||||
}
|
||||
|
||||
export interface MovedTeamProps {
|
||||
from: Team;
|
||||
to: Team;
|
||||
}
|
||||
|
||||
export interface DragCollectProps {
|
||||
getItem: () => { index: number };
|
||||
isOver: (options?: { shallow?: boolean }) => boolean;
|
||||
}
|
||||
|
||||
export interface TableExpandableDataProps {
|
||||
expanded: boolean;
|
||||
onExpand: (record: Team, event: React.MouseEvent<HTMLElement>) => void;
|
||||
expandable: boolean;
|
||||
record: Team;
|
||||
}
|
@ -54,16 +54,40 @@
|
||||
td {
|
||||
border-right: none;
|
||||
background: @white;
|
||||
margin-right: 10px;
|
||||
|
||||
.drag-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 6px;
|
||||
display: inline-flex;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expand-cell-icon-container {
|
||||
display: inline-flex;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.expand-cell-empty-icon-container {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-cell-with-append {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.ant-table-cell-row-hover {
|
||||
background: @body-dark-bg-color;
|
||||
.drag-icon {
|
||||
visibility: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed 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 DraggableBodyRow from '../components/TeamDetails/DraggableBodyRow';
|
||||
|
||||
export const DRAGGABLE_BODY_ROW = 'DraggableBodyRow';
|
||||
|
||||
export const TABLE_CONSTANTS = {
|
||||
body: {
|
||||
row: DraggableBodyRow,
|
||||
},
|
||||
};
|
@ -17,7 +17,7 @@ declare module 'Models' {
|
||||
import { TagLabel } from '../generated/type/tagLabel';
|
||||
import { Paging } from './../generated/type/paging';
|
||||
|
||||
export interface RestoreEntitiesRequestType {
|
||||
export interface RestoreRequestType {
|
||||
id: string;
|
||||
}
|
||||
|
||||
|
@ -381,6 +381,7 @@
|
||||
"hide": "Hide",
|
||||
"restore-team": "Restore Team",
|
||||
"remove": "Remove",
|
||||
"move-the-team": "Move the Team",
|
||||
"data-insight-plural": "Data Insights",
|
||||
"configure-entity": "Configure {{entity}}",
|
||||
"name-lowercase": "name",
|
||||
@ -536,6 +537,8 @@
|
||||
"delete-message-question-mark": "Delete Message?",
|
||||
"view-deleted-teams": "View all the Deleted Teams, which come under this Team.",
|
||||
"restore-deleted-team": " Restoring the Team will add all the metadata back to OpenMetadata",
|
||||
"team-moved-success": "Team moved successfully",
|
||||
"team-transfer-message": "Click on Confirm if you’d like to move {{from}} team under {{to}} team.",
|
||||
"create-new-glossary-guide": "A Glossary is a controlled vocabulary used to define the concepts and terminology in an organization. Glossaries can be specific to a certain domain (for e.g., Business Glossary, Technical Glossary). In the glossary, the standard terms and concepts can be defined along with the synonyms, and related terms. Control can be established over how and who can add the terms in the glossary.",
|
||||
"no-notification-found": "No notifications Found",
|
||||
"enables-end-to-end-metadata-management": "Enables end-to-end metadata management with data discovery, data duality, observability, and people collaboration",
|
||||
@ -573,7 +576,8 @@
|
||||
"leave-team-error": "Error while leaving the team!",
|
||||
"no-query-available": "No query available",
|
||||
"unexpected-response": "Unexpected response from server!",
|
||||
"ingestion-workflow-operation-error": "Error while {{operation}} ingestion workflow {{displayName}}"
|
||||
"ingestion-workflow-operation-error": "Error while {{operation}} ingestion workflow {{displayName}}",
|
||||
"team-moved-error": "Error while moving team"
|
||||
},
|
||||
"url": {}
|
||||
}
|
||||
|
191
openmetadata-ui/src/main/resources/ui/src/mocks/Teams.mock.ts
Normal file
191
openmetadata-ui/src/main/resources/ui/src/mocks/Teams.mock.ts
Normal file
@ -0,0 +1,191 @@
|
||||
/* Copyright 2022 Collate
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
export const MOCK_CURRENT_TEAM = {
|
||||
childrenCount: 22,
|
||||
defaultRoles: [
|
||||
{
|
||||
deleted: false,
|
||||
description:
|
||||
'Users with Data Consumer role use different data assets for their day to day work.',
|
||||
displayName: 'Data Consumer',
|
||||
fullyQualifiedName: 'DataConsumer',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/roles/1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
id: '1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
name: 'DataConsumer',
|
||||
type: 'role',
|
||||
},
|
||||
],
|
||||
deleted: false,
|
||||
description:
|
||||
'Organization under which all the other team hierarchy is created',
|
||||
displayName: 'Organization',
|
||||
fullyQualifiedName: 'Organization',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/f9578f16-363a-4788-80fb-d05816c9e169',
|
||||
id: 'f9578f16-363a-4788-80fb-d05816c9e169',
|
||||
inheritedRoles: [],
|
||||
isJoinable: false,
|
||||
name: 'Organization',
|
||||
owns: [],
|
||||
parents: [],
|
||||
policies: [
|
||||
{
|
||||
deleted: false,
|
||||
description: 'Policy for all the users of an organization.',
|
||||
displayName: 'Organization Policy',
|
||||
fullyQualifiedName: 'OrganizationPolicy',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/policies/09f4480c-ef57-4239-b2aa-c87053ad4f46',
|
||||
id: '09f4480c-ef57-4239-b2aa-c87053ad4f46',
|
||||
name: 'OrganizationPolicy',
|
||||
type: 'policy',
|
||||
},
|
||||
],
|
||||
teamType: undefined,
|
||||
updatedAt: 1669719624263,
|
||||
updatedBy: 'ag939431',
|
||||
users: [],
|
||||
version: 2.4,
|
||||
};
|
||||
|
||||
export const MOCK_TABLE_DATA = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: undefined,
|
||||
childrenCount: 0,
|
||||
defaultRoles: [],
|
||||
deleted: false,
|
||||
fullyQualifiedName: 'Applications',
|
||||
href: 'http://localhost:8585/api/v1/teams/eb4b1b74-d30e-4bfa-8409-dac15db3cc32',
|
||||
id: 'eb4b1b74-d30e-4bfa-8409-dac15db3cc32',
|
||||
inheritedRoles: [],
|
||||
isJoinable: true,
|
||||
key: 'Applications',
|
||||
name: 'Applications',
|
||||
owns: [],
|
||||
teamType: 'Group',
|
||||
updatedAt: 1670390160760,
|
||||
updatedBy: 'admin',
|
||||
userCount: 12,
|
||||
version: 0.1,
|
||||
type: 'BusinessUnit',
|
||||
},
|
||||
{
|
||||
children: undefined,
|
||||
childrenCount: 3,
|
||||
defaultRoles: [],
|
||||
deleted: false,
|
||||
fullyQualifiedName: 'Infrastructure',
|
||||
href: 'http://localhost:8585/api/v1/teams/c8cc8922-8917-4d33-94e3-d9d257dd8830',
|
||||
id: 'c8cc8922-8917-4d33-94e3-d9d257dd8830',
|
||||
inheritedRoles: [],
|
||||
isJoinable: true,
|
||||
key: 'Infrastructure',
|
||||
name: 'Infrastructure',
|
||||
owns: [],
|
||||
teamType: 'BusinessUnit',
|
||||
type: 'BusinessUnit',
|
||||
updatedAt: 1670390159742,
|
||||
updatedBy: 'admin',
|
||||
userCount: 20,
|
||||
version: 0.1,
|
||||
},
|
||||
],
|
||||
childrenCount: 4,
|
||||
defaultRoles: [],
|
||||
deleted: false,
|
||||
fullyQualifiedName: 'Engineering',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/49d060a2-ad14-48a7-840a-836cd99aaffb',
|
||||
id: '49d060a2-ad14-48a7-840a-836cd99aaffb',
|
||||
inheritedRoles: [
|
||||
{
|
||||
deleted: false,
|
||||
description:
|
||||
'Users with Data Consumer role use different data assets for their day to day work.',
|
||||
displayName: 'Data Consumer',
|
||||
fullyQualifiedName: 'DataConsumer',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/roles/1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
id: '1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
name: 'DataConsumer',
|
||||
type: 'role',
|
||||
},
|
||||
],
|
||||
isJoinable: true,
|
||||
key: 'Engineering',
|
||||
name: 'Engineering',
|
||||
owns: [],
|
||||
teamType: undefined,
|
||||
updatedAt: 1670312015218,
|
||||
updatedBy: 'ingestion-bot',
|
||||
userCount: 50,
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
childrenCount: 3,
|
||||
defaultRoles: [],
|
||||
deleted: false,
|
||||
fullyQualifiedName: 'Finance',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/b201a5b2-b0e8-461d-9fa1-cd5212d09eee',
|
||||
id: 'b201a5b2-b0e8-461d-9fa1-cd5212d09eee',
|
||||
inheritedRoles: [
|
||||
{
|
||||
deleted: false,
|
||||
description:
|
||||
'Users with Data Consumer role use different data assets for their day to day work.',
|
||||
displayName: 'Data Consumer',
|
||||
fullyQualifiedName: 'DataConsumer',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/roles/1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
id: '1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
name: 'DataConsumer',
|
||||
type: 'role',
|
||||
},
|
||||
],
|
||||
isJoinable: true,
|
||||
key: 'Finance',
|
||||
name: 'Finance',
|
||||
owns: [],
|
||||
teamType: undefined,
|
||||
updatedAt: 1670312016093,
|
||||
updatedBy: 'ingestion-bot',
|
||||
userCount: 2,
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
childrenCount: 2,
|
||||
defaultRoles: [],
|
||||
deleted: false,
|
||||
fullyQualifiedName: 'Legal',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/e64afbd0-aab5-4aed-952d-c5a5b8ba06bb',
|
||||
id: 'e64afbd0-aab5-4aed-952d-c5a5b8ba06bb',
|
||||
inheritedRoles: [
|
||||
{
|
||||
deleted: false,
|
||||
description:
|
||||
'Users with Data Consumer role use different data assets for their day to day work.',
|
||||
displayName: 'Legal',
|
||||
fullyQualifiedName: 'Legal',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/roles/1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
id: '1497b0cf-cb5f-42c2-8e13-3ab68b90bfa0',
|
||||
name: 'Legal',
|
||||
type: 'role',
|
||||
},
|
||||
],
|
||||
isJoinable: true,
|
||||
key: 'Marketing',
|
||||
name: 'Marketing',
|
||||
owns: [],
|
||||
teamType: undefined,
|
||||
updatedAt: 1670312016516,
|
||||
updatedBy: 'ingestion-bot',
|
||||
userCount: 3,
|
||||
},
|
||||
];
|
@ -32,6 +32,9 @@
|
||||
.d-flex {
|
||||
display: flex;
|
||||
}
|
||||
.d-inline-flex {
|
||||
display: inline-flex;
|
||||
}
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ import IconDeployIngestion from '../assets/svg/deploy-ingestion.svg';
|
||||
import IconDocPrimary from '../assets/svg/doc-primary.svg';
|
||||
import IconDocWhite from '../assets/svg/doc-white.svg';
|
||||
import IconDoc from '../assets/svg/doc.svg';
|
||||
import IconDrag from '../assets/svg/drag.svg';
|
||||
import IconEditBlack from '../assets/svg/edit-black.svg';
|
||||
import IconEditOutlinePrimary from '../assets/svg/edit-outline-primery.svg';
|
||||
import IconEditPrimary from '../assets/svg/edit-primary.svg';
|
||||
@ -397,6 +398,7 @@ export const Icons = {
|
||||
HIDE_PASSWORD: 'hide-password',
|
||||
ARROW_RIGHT_LIGHT: 'arrow-right-light',
|
||||
ARROW_DOWN_LIGHT: 'arrow-down-light',
|
||||
DRAG: 'drag',
|
||||
};
|
||||
|
||||
const SVGIcons: FunctionComponent<Props> = ({ icon, ...props }: Props) => {
|
||||
@ -509,6 +511,11 @@ const SVGIcons: FunctionComponent<Props> = ({ icon, ...props }: Props) => {
|
||||
case Icons.FEED:
|
||||
IconComponent = IconFeed;
|
||||
|
||||
break;
|
||||
|
||||
case Icons.DRAG:
|
||||
IconComponent = IconDrag;
|
||||
|
||||
break;
|
||||
case Icons.THUMBSUP:
|
||||
IconComponent = IconThumbsUp;
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import { t } from 'i18next';
|
||||
import { cloneDeep, isEmpty, isNil, isUndefined, omit } from 'lodash';
|
||||
import { cloneDeep, isNil, isUndefined, omit } from 'lodash';
|
||||
import { CreateTeam } from '../generated/api/teams/createTeam';
|
||||
import {
|
||||
EntityReference,
|
||||
@ -53,10 +53,7 @@ const getEntityValue = (value: EntityReference[] | undefined) => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getRestoreTeamData = (
|
||||
team: Team,
|
||||
childTeams: Team[]
|
||||
): CreateTeam => {
|
||||
export const getMovedTeamData = (team: Team, parents: string[]): CreateTeam => {
|
||||
const userDetails = omit(cloneDeep(team), [
|
||||
'id',
|
||||
'fullyQualifiedName',
|
||||
@ -70,18 +67,20 @@ export const getRestoreTeamData = (
|
||||
'changeDescription',
|
||||
'deleted',
|
||||
'inheritedRoles',
|
||||
'key',
|
||||
]) as Team;
|
||||
|
||||
const { parents, policies, users, defaultRoles } = userDetails;
|
||||
const { policies, users, defaultRoles, children } = userDetails;
|
||||
|
||||
return {
|
||||
...userDetails,
|
||||
teamType: userDetails.teamType as TeamType,
|
||||
defaultRoles: getEntityValue(defaultRoles),
|
||||
children: isEmpty(childTeams)
|
||||
? undefined
|
||||
: getEntityIdArray(childTeams as EntityReference[]),
|
||||
parents: getEntityValue(parents),
|
||||
children:
|
||||
userDetails.teamType == TeamType.Group
|
||||
? undefined
|
||||
: getEntityValue(children),
|
||||
parents: parents,
|
||||
policies: getEntityValue(policies),
|
||||
users: getEntityValue(users),
|
||||
};
|
||||
|
@ -2856,6 +2856,21 @@
|
||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.15.tgz#6a9d143f7f4f49db2d782f9e1c8839a29b43ae23"
|
||||
integrity sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA==
|
||||
|
||||
"@react-dnd/asap@^4.0.0":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab"
|
||||
integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==
|
||||
|
||||
"@react-dnd/invariant@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-2.0.0.tgz#09d2e81cd39e0e767d7da62df9325860f24e517e"
|
||||
integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==
|
||||
|
||||
"@react-dnd/shallowequal@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a"
|
||||
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
|
||||
|
||||
"@rc-component/portal@^1.0.0-6", "@rc-component/portal@^1.0.0-8":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-1.0.3.tgz#3aa2c229a7a20ac2412d864e8977e6377973416e"
|
||||
@ -6511,6 +6526,24 @@ dlv@^1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
|
||||
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
||||
|
||||
dnd-core@14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.0.tgz#973ab3470d0a9ac5a0fa9021c4feba93ad12347d"
|
||||
integrity sha512-wTDYKyjSqWuYw3ZG0GJ7k+UIfzxTNoZLjDrut37PbcPGNfwhlKYlPUqjAKUjOOv80izshUiqusaKgJPItXSevA==
|
||||
dependencies:
|
||||
"@react-dnd/asap" "^4.0.0"
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
redux "^4.0.5"
|
||||
|
||||
dnd-core@14.0.1:
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.1.tgz#76d000e41c494983210fb20a48b835f81a203c2e"
|
||||
integrity sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==
|
||||
dependencies:
|
||||
"@react-dnd/asap" "^4.0.0"
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
redux "^4.1.1"
|
||||
|
||||
dns-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
|
||||
@ -12417,6 +12450,24 @@ react-copy-to-clipboard@^5.0.4:
|
||||
copy-to-clipboard "^3"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-dnd-html5-backend@14.0.2:
|
||||
version "14.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.2.tgz#25019388f6abdeeda3a6fea835dff155abb2085c"
|
||||
integrity sha512-QgN6rYrOm4UUj6tIvN8ovImu6uP48xBXF2rzVsp6tvj6d5XQ7OjHI4SJ/ZgGobOneRAU3WCX4f8DGCYx0tuhlw==
|
||||
dependencies:
|
||||
dnd-core "14.0.1"
|
||||
|
||||
react-dnd@14.0.2:
|
||||
version "14.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.2.tgz#57266baec92b887301f81fa3b77f87168d159733"
|
||||
integrity sha512-JoEL78sBCg8SzjOKMlkR70GWaPORudhWuTNqJ56lb2P8Vq0eM2+er3ZrMGiSDhOmzaRPuA9SNBz46nHCrjn11A==
|
||||
dependencies:
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
"@react-dnd/shallowequal" "^2.0.0"
|
||||
dnd-core "14.0.0"
|
||||
fast-deep-equal "^3.1.3"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
|
||||
react-dom@^16.14.0:
|
||||
version "16.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
|
||||
@ -12823,7 +12874,7 @@ reduce-css-calc@^2.1.8:
|
||||
css-unit-converter "^1.1.1"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
redux@^4.0.0, redux@^4.1.0:
|
||||
redux@^4.0.0, redux@^4.0.5, redux@^4.1.0, redux@^4.1.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13"
|
||||
integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==
|
||||
|
Loading…
x
Reference in New Issue
Block a user