Query.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import { FC, useEffect, useState, useRef, useMemo } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import EmptyCard from '../../components/cards/EmptyCard';
  4. import icons from '../../components/icons/Icons';
  5. import CustomButton from '../../components/customButton/CustomButton';
  6. import MilvusGrid from '../../components/grid/Grid';
  7. import { getQueryStyles } from './Styles';
  8. import Filter from '../../components/advancedSearch';
  9. import { CollectionHttp } from '../../http/Collection';
  10. import { FieldHttp } from '../../http/Field';
  11. import { usePaginationHook } from '../../hooks/Pagination';
  12. const Query: FC<{
  13. collectionName: string;
  14. }> = ({ collectionName }) => {
  15. const [fields, setFields] = useState<any[]>([]);
  16. const [expression, setExpression] = useState('');
  17. const [tableLoading, setTableLoading] = useState<any>();
  18. const [queryResult, setQueryResult] = useState<any>();
  19. const VectorSearchIcon = icons.vectorSearch;
  20. const ResetIcon = icons.refresh;
  21. const { t: searchTrans } = useTranslation('search');
  22. const { t: collectionTrans } = useTranslation('collection');
  23. const { t: btnTrans } = useTranslation('btn');
  24. const classes = getQueryStyles();
  25. // Format result list
  26. const queryResultMemo = useMemo(
  27. () =>
  28. queryResult?.map((resultItem: { [key: string]: any }) => {
  29. // Iterate resultItem keys, then format vector(array) items.
  30. const tmp = Object.keys(resultItem).reduce(
  31. (prev: { [key: string]: any }, item: string) => {
  32. if (Array.isArray(resultItem[item])) {
  33. const list2Str = `[${resultItem[item]}]`;
  34. prev[item] = (
  35. <div className={classes.vectorTableCell} title={list2Str}>
  36. {list2Str}
  37. </div>
  38. );
  39. } else {
  40. prev[item] = resultItem[item];
  41. }
  42. return prev;
  43. },
  44. {}
  45. );
  46. return tmp;
  47. }),
  48. [queryResult, classes.vectorTableCell]
  49. );
  50. const {
  51. pageSize,
  52. handlePageSize,
  53. currentPage,
  54. handleCurrentPage,
  55. total,
  56. data: result,
  57. order,
  58. orderBy,
  59. handleGridSort,
  60. } = usePaginationHook(queryResultMemo || []);
  61. const handlePageChange = (e: any, page: number) => {
  62. handleCurrentPage(page);
  63. };
  64. const getFields = async (collectionName: string) => {
  65. const schemaList = await FieldHttp.getFields(collectionName);
  66. const nameList = schemaList.map(i => ({
  67. name: i.name,
  68. type: i.data_type.includes('Int') ? 'int' : 'float',
  69. }));
  70. setFields(nameList);
  71. };
  72. // Get fields at first or collection name changed.
  73. useEffect(() => {
  74. collectionName && getFields(collectionName);
  75. }, [collectionName]);
  76. const filterRef = useRef();
  77. const handleFilterReset = () => {
  78. const currentFilter: any = filterRef.current;
  79. currentFilter?.getReset();
  80. setExpression('');
  81. setTableLoading(null);
  82. setQueryResult(null);
  83. };
  84. const handleFilterSubmit = (expression: string) => {
  85. setExpression(expression);
  86. };
  87. const handleQuery = async () => {
  88. setTableLoading(true);
  89. try {
  90. const res = await CollectionHttp.queryData(collectionName, {
  91. expr: expression,
  92. output_fields: fields.map(i => i.name),
  93. });
  94. setTableLoading(false);
  95. const result = res.data;
  96. setQueryResult(result);
  97. } catch (err) {
  98. setTableLoading(false);
  99. }
  100. };
  101. return (
  102. <div className={classes.root}>
  103. <div className={classes.toolbar}>
  104. <div className="left">
  105. <div>{`${
  106. expression || 'Please enter your query or use advanced filter ->'
  107. }`}</div>
  108. <Filter
  109. ref={filterRef}
  110. title="Advanced Filter"
  111. fields={fields}
  112. filterDisabled={false}
  113. onSubmit={handleFilterSubmit}
  114. showTitle={false}
  115. showTooltip={false}
  116. />
  117. </div>
  118. <div className="right">
  119. <CustomButton className="btn" onClick={handleFilterReset}>
  120. <ResetIcon classes={{ root: 'icon' }} />
  121. {btnTrans('reset')}
  122. </CustomButton>
  123. <CustomButton
  124. variant="contained"
  125. disabled={!expression}
  126. onClick={() => handleQuery()}
  127. >
  128. {btnTrans('query')}
  129. </CustomButton>
  130. </div>
  131. </div>
  132. {tableLoading || queryResult ? (
  133. <MilvusGrid
  134. toolbarConfigs={[]}
  135. colDefinitions={fields.map(i => ({
  136. id: i.name,
  137. align: 'left',
  138. disablePadding: false,
  139. label: i.name,
  140. }))}
  141. primaryKey={fields.find(i => i.is_primary_key)?.name}
  142. openCheckBox={false}
  143. isLoading={!!tableLoading}
  144. rows={result}
  145. rowCount={total}
  146. page={currentPage}
  147. onChangePage={handlePageChange}
  148. rowsPerPage={pageSize}
  149. setRowsPerPage={handlePageSize}
  150. orderBy={orderBy}
  151. order={order}
  152. handleSort={handleGridSort}
  153. />
  154. ) : (
  155. <EmptyCard
  156. wrapperClass={`page-empty-card ${classes.emptyCard}`}
  157. icon={<VectorSearchIcon />}
  158. text={
  159. queryResult !== null
  160. ? searchTrans('empty')
  161. : collectionTrans('startTip')
  162. }
  163. />
  164. )}
  165. </div>
  166. );
  167. };
  168. export default Query;