Skip to content

Commit

Permalink
Support duplicate collection (no copy data) (#346)
Browse files Browse the repository at this point in the history
* duplicate dialog part1

Signed-off-by: ryjiang <[email protected]>

* finish duplicate

Signed-off-by: ryjiang <[email protected]>

* update i18n

Signed-off-by: ryjiang <[email protected]>

* move convert schema to utils

Signed-off-by: ryjiang <[email protected]>

* fix validation

Signed-off-by: ryjiang <[email protected]>

---------

Signed-off-by: ryjiang <[email protected]>
  • Loading branch information
shanghaikid authored Dec 27, 2023
1 parent 8978d39 commit b7e76e0
Show file tree
Hide file tree
Showing 15 changed files with 349 additions and 76 deletions.
10 changes: 10 additions & 0 deletions client/src/http/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ export class Collection extends BaseModel implements CollectionData {
});
}

static duplicate(
collectionName: string,
params: { new_collection_name: string }
) {
return super.create({
path: `${this.COLLECTIONS_URL}/${collectionName}/duplicate`,
data: params,
});
}

static getStatistics() {
return super.search({ path: this.COLLECTIONS_STATISTICS_URL, params: {} });
}
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/cn/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const btnTrans = {
importing: '导入中...',
example: '生成随机向量',
rename: '重命名',
duplicate: '复制',
};

export default btnTrans;
9 changes: 8 additions & 1 deletion client/src/i18n/cn/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ const collectionTrans = {
delete: '删除',
deleteTooltip: '请至少选择一个要删除的项目。',
rename: '重命名',
renameTooltip: '请选择一个要重命名的项目。',
renameTooltip: '请选择一个要重命名的Collection。',
duplicate: '复制',
duplicateTooltip: '请选择一个要复制的Collection。',
newColName: '新的Collection名称',
alias: '别名',
aliasTooltip: '请选择一个Collection创建别名',
Expand All @@ -36,6 +38,8 @@ const collectionTrans = {
consistencyLevelInfo:
'一致性是指确保每个节点或副本在给定时间写入或读取数据时具有相同数据视图的属性。',
entityCountInfo: '大约的Entity数量。',
duplicateCollectionInfo:
'复制Collection不会复制Collection中的数据。它只会使用现有的Schema创建一个新的Collection。',

// create dialog
createTitle: '创建Collection',
Expand Down Expand Up @@ -104,6 +108,9 @@ const collectionTrans = {
newColNamePlaceholder: '新的Collection名称',
newNameInfo: '只允许数字,字母和下划线。',

// duplicate dialog
duplicateNameExist: 'Collection已经存在。',

// segment
segments: '数据段',
segPState: '持久数据段状态',
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/cn/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const dialogTrans = {
deleteTitle: `删除 {{type}}`,
renameTitle: `重命名 {{type}}`,
releaseTitle: `发布 {{type}}`,
duplicateTitle: `复制 {{type}}`,
createAlias: `为 {{type}} 创建别名`,
compact: `压缩Collection {{type}}`,
loadTitle: `加载 {{type}}`,
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/en/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const btnTrans = {
importing: 'Importing...',
example: 'Generate random vector',
rename: 'Rename',
duplicate: 'Duplicate',
};

export default btnTrans;
9 changes: 8 additions & 1 deletion client/src/i18n/en/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ const collectionTrans = {
delete: 'delete',
deleteTooltip: 'Please select at least one item to delete.',
rename: 'rename',
renameTooltip: 'Please select one item to rename.',
renameTooltip: 'Please select one collection to rename.',
duplicate: 'duplicate',
duplicateTooltip: 'Please select one collection to duplicate.',
newColName: 'New Collection Name',
alias: 'Alias',
aliasTooltip: 'Please select one collection to create alias',
Expand All @@ -36,6 +38,8 @@ const collectionTrans = {
consistencyLevelInfo:
'Consistency refers to the property that ensures every node or replica has the same view of data when writing or reading data at a given time.',
entityCountInfo: 'Approximately entity count.',
duplicateCollectionInfo:
'Duplicating a collection does not copy the data within the collection. It only creates a new collection using the existing schema.',

// create dialog
createTitle: 'Create Collection',
Expand Down Expand Up @@ -107,6 +111,9 @@ const collectionTrans = {
newColNamePlaceholder: 'New Collection Name',
newNameInfo: 'Only numbers, letters, and underscores are allowed.',

// duplicate dialog
duplicateNameExist: 'A collection with this name already exists.',

// segment
segments: 'Segments',
segPState: 'Persistent Segment State',
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/en/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const dialogTrans = {
deleteTitle: `Drop {{type}}`,
renameTitle: `Rename {{type}}`,
releaseTitle: `Release {{type}}`,
duplicateTitle: `Duplicate {{type}}`,
createAlias: `Create alias for {{type}}`,
compact: `Compact collection {{type}}`,
loadTitle: `Load {{type}}`,
Expand Down
169 changes: 98 additions & 71 deletions client/src/pages/collections/Collections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import LoadCollectionDialog from '../dialogs/LoadCollectionDialog';
import ReleaseCollectionDialog from '../dialogs/ReleaseCollectionDialog';
import DropCollectionDialog from '../dialogs/DropCollectionDialog';
import RenameCollectionDialog from '../dialogs/RenameCollectionDialog';
import DuplicateCollectionDialog from '../dialogs/DuplicateCollectionDailog';
import InsertDialog from '../dialogs/insert/Dialog';
import ImportSampleDialog from '../dialogs/ImportSampleDialog';
import { LOADING_STATE } from '@/consts';
Expand Down Expand Up @@ -217,12 +218,26 @@ const Collections = () => {
v.status === LOADING_STATE.UNLOADED ? (
<LoadCollectionDialog
collection={v.collectionName}
onLoad={onLoad}
onLoad={async () => {
openSnackBar(
successTrans('load', {
name: collectionTrans('collection'),
})
);
await fetchData();
}}
/>
) : (
<ReleaseCollectionDialog
collection={v.collectionName}
onRelease={onRelease}
onRelease={async () => {
openSnackBar(
successTrans('release', {
name: collectionTrans('collection'),
})
);
await fetchData();
}}
/>
),
},
Expand Down Expand Up @@ -257,70 +272,6 @@ const Collections = () => {
orderBy,
} = usePaginationHook(formatCollections);

const handleInsert = async (
collectionName: string,
partitionName: string,
fieldData: any[]
): Promise<{ result: boolean; msg: string }> => {
const param: InsertDataParam = {
partition_name: partitionName,
fields_data: fieldData,
};
try {
await DataService.insertData(collectionName, param);
await DataService.flush(collectionName);
// update collections
fetchData();
return { result: true, msg: '' };
} catch (err: any) {
const {
response: {
data: { message },
},
} = err;
return { result: false, msg: message || '' };
}
};

const onCreate = () => {
openSnackBar(
successTrans('create', { name: collectionTrans('collection') })
);
fetchData();
};

const onRelease = async () => {
openSnackBar(
successTrans('release', { name: collectionTrans('collection') })
);
fetchData();
};

const onLoad = () => {
openSnackBar(successTrans('load', { name: collectionTrans('collection') }));
fetchData();
};

const onDelete = () => {
openSnackBar(
successTrans('delete', { name: collectionTrans('collection') })
);
fetchData();
setSelectedCollections([]);
};

const onRename = () => {
openSnackBar(
successTrans('rename', { name: collectionTrans('collection') })
);
fetchData();
setSelectedCollections([]);
};

const handleSearch = (value: string) => {
setSearch(value);
};

const toolbarConfigs: ToolBarConfig[] = [
{
label: collectionTrans('create'),
Expand All @@ -329,7 +280,18 @@ const Collections = () => {
open: true,
type: 'custom',
params: {
component: <CreateCollectionDialog onCreate={onCreate} />,
component: (
<CreateCollectionDialog
onCreate={async () => {
openSnackBar(
successTrans('create', {
name: collectionTrans('collection'),
})
);
await fetchData();
}}
/>
),
},
});
},
Expand All @@ -354,7 +316,30 @@ const Collections = () => {
}
// user can't select partition on collection page, so default value is ''
defaultSelectedPartition={''}
handleInsert={handleInsert}
handleInsert={async (
collectionName: string,
partitionName: string,
fieldData: any[]
): Promise<{ result: boolean; msg: string }> => {
const param: InsertDataParam = {
partition_name: partitionName,
fields_data: fieldData,
};
try {
await DataService.insertData(collectionName, param);
await DataService.flush(collectionName);
// update collections
fetchData();
return { result: true, msg: '' };
} catch (err: any) {
const {
response: {
data: { message },
},
} = err;
return { result: false, msg: message || '' };
}
}}
/>
),
},
Expand All @@ -378,8 +363,42 @@ const Collections = () => {
params: {
component: (
<RenameCollectionDialog
cb={onRename}
cb={async () => {
openSnackBar(
successTrans('rename', {
name: collectionTrans('collection'),
})
);
await fetchData();
setSelectedCollections([]);
}}
collectionName={selectedCollections[0].collectionName}
/>
),
},
});
},
label: collectionTrans('rename'),
// tooltip: collectionTrans('deleteTooltip'),
disabledTooltip: collectionTrans('renameTooltip'),
disabled: data => data.length !== 1,
},
{
icon: 'copy',
type: 'iconBtn',
onClick: () => {
setDialog({
open: true,
type: 'custom',
params: {
component: (
<DuplicateCollectionDialog
cb={async () => {
setSelectedCollections([]);
await fetchData();
}}
collectionName={selectedCollections[0].collectionName}
collections={collections}
/>
),
},
Expand All @@ -399,7 +418,15 @@ const Collections = () => {
params: {
component: (
<DropCollectionDialog
onDelete={onDelete}
onDelete={async () => {
openSnackBar(
successTrans('delete', {
name: collectionTrans('collection'),
})
);
await fetchData();
setSelectedCollections([]);
}}
collections={selectedCollections}
/>
),
Expand Down Expand Up @@ -428,7 +455,7 @@ const Collections = () => {
icon: 'search',
searchText: search,
onSearch: (value: string) => {
handleSearch(value);
setSearch(value);
},
},
];
Expand Down
Loading

0 comments on commit b7e76e0

Please sign in to comment.