diff --git a/web/e2e/project/asset.spec.ts b/web/e2e/project/asset.spec.ts index dc094ec1ad..9b5ef229d3 100644 --- a/web/e2e/project/asset.spec.ts +++ b/web/e2e/project/asset.spec.ts @@ -27,12 +27,12 @@ test("Asset CRUD and Searching has succeeded", async ({ page }) => { await expect(page.getByRole("alert").last()).toContainText("Successfully added asset!"); await closeNotification(page); await expect(page.getByText(uploadFileName)).toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("no asset"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("no asset"); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByText(uploadFileName)).not.toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill(""); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill(""); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByText(uploadFileName)).toBeVisible(); await page.getByLabel("edit").locator("svg").click(); diff --git a/web/e2e/project/content.spec.ts b/web/e2e/project/content.spec.ts index cb3a047932..1f4a71eeb0 100644 --- a/web/e2e/project/content.spec.ts +++ b/web/e2e/project/content.spec.ts @@ -17,12 +17,7 @@ test.afterEach(async ({ page }) => { }); test("Item CRUD and searching has succeeded", async ({ page }) => { - await page - .locator("li") - .filter({ hasText: "TextHeading and titles, one-" }) - .locator("div") - .first() - .click(); + await page.locator("li").filter({ hasText: "Text" }).locator("div").first().click(); await handleFieldForm(page, "text"); await closeNotification(page); await page.getByText("Content").click(); @@ -34,11 +29,11 @@ test("Item CRUD and searching has succeeded", async ({ page }) => { await closeNotification(page); await page.getByLabel("Back").click(); await expect(page.getByRole("cell", { name: "text", exact: true })).toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("no field"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("no field"); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByRole("cell", { name: "text", exact: true })).not.toBeVisible(); - await page.getByPlaceholder("Please enter").fill(""); + await page.getByPlaceholder("input search text").fill(""); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByRole("cell", { name: "text", exact: true })).toBeVisible(); await page.getByRole("link", { name: "edit", exact: true }).click(); diff --git a/web/e2e/project/item/fields/asset.spec.ts b/web/e2e/project/item/fields/asset.spec.ts index d66ba6b2f3..cd4facb9b5 100644 --- a/web/e2e/project/item/fields/asset.spec.ts +++ b/web/e2e/project/item/fields/asset.spec.ts @@ -96,12 +96,12 @@ test("Asset field editing has succeeded", async ({ page }) => { await expect(page.getByRole("button", { name: uploadFileName_1, exact: true })).toBeVisible(); await page.getByLabel("Default value").getByRole("button").nth(3).click(); await page.getByRole("button", { name: "Asset" }).click(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("no asset"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("no asset"); await page.getByRole("button", { name: "search" }).click(); await expect(page.locator(".ant-table-row").first()).not.toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill(""); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill(""); await page.getByRole("button", { name: "search" }).click(); await page.locator(".ant-table-row > td").first().getByRole("button").hover(); await page.locator(".ant-table-row > td").first().getByRole("button").click(); diff --git a/web/e2e/project/request.spec.ts b/web/e2e/project/request.spec.ts index 0e3669ac03..faddec7308 100644 --- a/web/e2e/project/request.spec.ts +++ b/web/e2e/project/request.spec.ts @@ -30,12 +30,12 @@ test("Request creating, searching, updating reviewer, and approving has succeede await page.getByText("Request", { exact: true }).click(); await expect(page.getByText(requestTitle, { exact: true })).toBeVisible(); await expect(page.getByText("WAITING")).toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("no request"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("no request"); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByText(requestTitle, { exact: true })).not.toBeVisible(); await expect(page.getByText("WAITING")).not.toBeVisible(); - await page.getByPlaceholder("Please enter").fill(""); + await page.getByPlaceholder("input search text").fill(""); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByText(requestTitle, { exact: true })).toBeVisible(); await expect(page.getByText("WAITING")).toBeVisible(); diff --git a/web/e2e/settings/integrations.spec.ts b/web/e2e/settings/integrations.spec.ts index 90c12e8230..5452326960 100644 --- a/web/e2e/settings/integrations.spec.ts +++ b/web/e2e/settings/integrations.spec.ts @@ -32,8 +32,8 @@ test("Integration CRUD and searching has succeeded", async ({ reearth, page }) = ); await closeNotification(page); await expect(page.getByRole("cell", { name: "e2e integration name", exact: true })).toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("e2e integration name"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("e2e integration name"); await page.getByRole("button", { name: "search" }).click(); await page.getByRole("cell", { name: "setting" }).locator("svg").click(); await page @@ -48,14 +48,14 @@ test("Integration CRUD and searching has succeeded", async ({ reearth, page }) = ); await closeNotification(page); await expect(page.getByRole("cell", { name: "WRITER" })).toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("no integration"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("no integration"); await page.getByRole("button", { name: "search" }).click(); await expect( page.getByRole("cell", { name: "e2e integration name", exact: true }), ).not.toBeVisible(); - await page.getByPlaceholder("Please enter").click(); - await page.getByPlaceholder("Please enter").fill("e2e integration name"); + await page.getByPlaceholder("input search text").click(); + await page.getByPlaceholder("input search text").fill("e2e integration name"); await page.getByRole("button", { name: "search" }).click(); await expect(page.getByRole("cell", { name: "e2e integration name", exact: true })).toBeVisible(); await page.getByLabel("", { exact: true }).check(); diff --git a/web/src/components/molecules/Asset/AssetList/index.tsx b/web/src/components/molecules/Asset/AssetList/index.tsx index 630bef4bf6..5a17889397 100644 --- a/web/src/components/molecules/Asset/AssetList/index.tsx +++ b/web/src/components/molecules/Asset/AssetList/index.tsx @@ -31,7 +31,6 @@ type Props = { totalCount: number; page: number; pageSize: number; - searchTerm: string; onAssetItemSelect: (item: AssetItem) => void; onAssetSelect: (assetId: string) => void; onUploadModalCancel: () => void; @@ -65,7 +64,6 @@ const AssetList: React.FC = ({ uploadType, selectedAsset, totalCount, - searchTerm, page, pageSize, onAssetItemSelect, @@ -146,7 +144,6 @@ const AssetList: React.FC = ({ loading={loading} selectedAsset={selectedAsset} totalCount={totalCount} - searchTerm={searchTerm} page={page} pageSize={pageSize} onAssetItemSelect={onAssetItemSelect} diff --git a/web/src/components/molecules/Asset/AssetListTable/index.tsx b/web/src/components/molecules/Asset/AssetListTable/index.tsx index c190e8cf4d..e2058b020f 100644 --- a/web/src/components/molecules/Asset/AssetListTable/index.tsx +++ b/web/src/components/molecules/Asset/AssetListTable/index.tsx @@ -1,10 +1,11 @@ import styled from "@emotion/styled"; -import { Key } from "react"; +import { Key, useMemo, useCallback } from "react"; import Button from "@reearth-cms/components/atoms/Button"; import CustomTag from "@reearth-cms/components/atoms/CustomTag"; import DownloadButton from "@reearth-cms/components/atoms/DownloadButton"; import Icon from "@reearth-cms/components/atoms/Icon"; +import Input from "@reearth-cms/components/atoms/Input"; import Popover from "@reearth-cms/components/atoms/Popover"; import { ListToolBarProps, @@ -35,7 +36,6 @@ type Props = { loading: boolean; selectedAsset: Asset | undefined; totalCount: number; - searchTerm: string; page: number; pageSize: number; onAssetItemSelect: (item: AssetItem) => void; @@ -61,7 +61,6 @@ const AssetListTable: React.FC = ({ loading, selectedAsset, totalCount, - searchTerm, page, pageSize, onAssetItemSelect, @@ -75,189 +74,208 @@ const AssetListTable: React.FC = ({ }) => { const t = useT(); - const columns: StretchColumn[] = [ - { - title: "", - render: (_, asset) => onEdit(asset.id)} />, - align: "center", - width: 48, - minWidth: 48, - }, - { - title: () => , - dataIndex: "commentsCount", - key: "commentsCount", - render: (_, asset) => { - return ( - onAssetSelect(asset.id)}> - - - ); + const columns: StretchColumn[] = useMemo( + () => [ + { + title: "", + render: (_, asset) => ( + onEdit(asset.id)} /> + ), + align: "center", + width: 48, + minWidth: 48, }, - align: "center", - width: 48, - minWidth: 48, - }, - { - title: t("File"), - dataIndex: "fileName", - key: "NAME", - sorter: true, - width: 340, - minWidth: 340, - ellipsis: true, - }, - { - title: t("Size"), - dataIndex: "size", - key: "SIZE", - sorter: true, - render: (_text, record) => bytesFormat(record.size), - width: 100, - minWidth: 100, - }, - { - title: t("Preview Type"), - dataIndex: "previewType", - key: "previewType", - width: 120, - minWidth: 120, - }, - { - title: t("Status"), - dataIndex: "archiveExtractionStatus", - key: "archiveExtractionStatus", - render: (_, asset) => { - const assetExtension = getExtension(asset.fileName); - return ( - compressedFileFormats.includes(assetExtension) && ( - - ) - ); - }, - width: 130, - minWidth: 130, - }, - { - title: t("Created At"), - dataIndex: "createdAt", - key: "DATE", - sorter: true, - render: (_text, record) => dateTimeFormat(record.createdAt), - width: 150, - minWidth: 150, - }, - { - title: t("Created By"), - dataIndex: "createdBy", - key: "createdBy", - render: (_, item) => ( - - - {item.createdBy} - - ), - width: 105, - minWidth: 105, - ellipsis: true, - }, - { - title: t("ID"), - dataIndex: "id", - key: "id", - width: 240, - minWidth: 240, - ellipsis: true, - }, - { - title: t("Linked to"), - key: "linkedTo", - render: (_, asset) => { - if (asset.items.length === 1) { + { + title: () => , + dataIndex: "commentsCount", + key: "commentsCount", + render: (_, asset) => { return ( - onAssetItemSelect(asset?.items[0])}> - {asset?.items[0].itemId} - - ); - } - if (asset.items.length > 1) { - const content = ( - <> - {asset.items.map(item => ( -
- -
- ))} - + onAssetSelect(asset.id)}> + + ); + }, + align: "center", + width: 48, + minWidth: 48, + }, + { + title: t("File"), + dataIndex: "fileName", + key: "NAME", + sorter: true, + width: 340, + minWidth: 340, + ellipsis: true, + }, + { + title: t("Size"), + dataIndex: "size", + key: "SIZE", + sorter: true, + render: (_text, record) => bytesFormat(record.size), + width: 100, + minWidth: 100, + }, + { + title: t("Preview Type"), + dataIndex: "previewType", + key: "previewType", + width: 120, + minWidth: 120, + }, + { + title: t("Status"), + dataIndex: "archiveExtractionStatus", + key: "archiveExtractionStatus", + render: (_, asset) => { + const assetExtension = getExtension(asset.fileName); return ( - - - x{asset.items.length} - - + compressedFileFormats.includes(assetExtension) && ( + + ) ); - } + }, + width: 130, + minWidth: 130, }, - width: 230, - minWidth: 230, - }, - ]; - - const options: OptionConfig = { - search: true, - fullScreen: true, - reload: onAssetsReload, - }; + { + title: t("Created At"), + dataIndex: "createdAt", + key: "DATE", + sorter: true, + render: (_text, record) => dateTimeFormat(record.createdAt), + width: 150, + minWidth: 150, + }, + { + title: t("Created By"), + dataIndex: "createdBy", + key: "createdBy", + render: (_, item) => ( + + + {item.createdBy} + + ), + width: 105, + minWidth: 105, + ellipsis: true, + }, + { + title: t("ID"), + dataIndex: "id", + key: "id", + width: 240, + minWidth: 240, + ellipsis: true, + }, + { + title: t("Linked to"), + key: "linkedTo", + render: (_, asset) => { + if (asset.items.length === 1) { + return ( + onAssetItemSelect(asset?.items[0])}> + {asset?.items[0].itemId} + + ); + } + if (asset.items.length > 1) { + const content = ( + <> + {asset.items.map(item => ( +
+ +
+ ))} + + ); + return ( + + + x{asset.items.length} + + + ); + } + }, + width: 230, + minWidth: 230, + }, + ], + [onAssetItemSelect, onAssetSelect, onEdit, selectedAsset?.id, t], + ); - const pagination: TablePaginationConfig = { - showSizeChanger: true, - current: page, - total: totalCount, - pageSize: pageSize, - }; + const options: OptionConfig = useMemo( + () => ({ + search: true, + fullScreen: true, + reload: onAssetsReload, + }), + [onAssetsReload], + ); - const rowSelection: TableRowSelection = { - selectedRowKeys: selection.selectedRowKeys, - onChange: (selectedRowKeys: any) => { - setSelection({ - ...selection, - selectedRowKeys: selectedRowKeys, - }); - }, - }; + const pagination: TablePaginationConfig = useMemo( + () => ({ + showSizeChanger: true, + current: page, + total: totalCount, + pageSize: pageSize, + }), + [page, pageSize, totalCount], + ); - const handleToolbarEvents: ListToolBarProps | undefined = { - search: { - defaultValue: searchTerm, - onSearch: (value: string) => { - if (value) { - onSearchTerm(value); - } else { - onSearchTerm(); - } + const rowSelection: TableRowSelection = useMemo( + () => ({ + selectedRowKeys: selection.selectedRowKeys, + onChange: (selectedRowKeys: any) => { + setSelection({ + ...selection, + selectedRowKeys: selectedRowKeys, + }); }, - }, - }; + }), + [selection, setSelection], + ); - const AlertOptions = (props: any) => { - return ( - - - {t("Deselect")} - - - onAssetDelete?.(props.selectedRowKeys)}> - {t("Delete")} - - - ); - }; + const toolbar: ListToolBarProps = useMemo( + () => ({ + search: ( + { + onSearchTerm(value); + }} + /> + ), + }), + [onSearchTerm, t], + ); + + const AlertOptions = useCallback( + (props: any) => { + return ( + + + {t("Deselect")} + + + onAssetDelete?.(props.selectedRowKeys)}> + {t("Delete")} + + + ); + }, + [onAssetDelete, t], + ); return ( = ({ rowKey="id" options={options} pagination={pagination} - toolbar={handleToolbarEvents} + toolbar={toolbar} rowSelection={rowSelection} loading={loading} onChange={(pagination, _, sorter: any) => { diff --git a/web/src/components/molecules/Asset/UploadModal/UploadModal.tsx b/web/src/components/molecules/Asset/UploadModal/UploadModal.tsx index 6bba6d36b5..7f5520693e 100644 --- a/web/src/components/molecules/Asset/UploadModal/UploadModal.tsx +++ b/web/src/components/molecules/Asset/UploadModal/UploadModal.tsx @@ -82,7 +82,7 @@ const UploadModal: React.FC = ({ diff --git a/web/src/components/molecules/Common/LinkAssetModal/LinkAssetModal.tsx b/web/src/components/molecules/Common/LinkAssetModal/LinkAssetModal.tsx index 54214cdefe..e43e9ae3e5 100644 --- a/web/src/components/molecules/Common/LinkAssetModal/LinkAssetModal.tsx +++ b/web/src/components/molecules/Common/LinkAssetModal/LinkAssetModal.tsx @@ -1,11 +1,11 @@ import styled from "@emotion/styled"; -import { useState, useRef, useCallback } from "react"; +import { useState, useRef, useCallback, useMemo } from "react"; import Button from "@reearth-cms/components/atoms/Button"; import Icon from "@reearth-cms/components/atoms/Icon"; import Input from "@reearth-cms/components/atoms/Input"; import Modal from "@reearth-cms/components/atoms/Modal"; -import ProTable, { +import { ProColumns, ListToolBarProps, OptionConfig, @@ -15,6 +15,7 @@ import { UploadProps, UploadFile } from "@reearth-cms/components/atoms/Upload"; import { UploadType } from "@reearth-cms/components/molecules/Asset/AssetList"; import { Asset } from "@reearth-cms/components/molecules/Asset/types"; import UploadAsset from "@reearth-cms/components/molecules/Asset/UploadAsset"; +import ResizableProTable from "@reearth-cms/components/molecules/Common/ResizableProTable"; import { ItemAsset } from "@reearth-cms/components/molecules/Content/types"; import { AssetSortType, @@ -23,11 +24,11 @@ import { import { useT } from "@reearth-cms/i18n"; import { dateTimeFormat, bytesFormat } from "@reearth-cms/utils/format"; +type StretchColumn = ProColumns & { minWidth: number }; + type Props = { - // modal props visible: boolean; onLinkAssetModalCancel: () => void; - // table props linkedAsset?: ItemAsset; assetList: Asset[]; fileList: UploadFile[]; @@ -86,33 +87,36 @@ const LinkAssetModal: React.FC = ({ const [hoveredAssetId, setHoveredAssetId] = useState(); const resetFlag = useRef(false); - const options: OptionConfig = { - search: true, - reload: onAssetsReload, - }; + const options: OptionConfig = useMemo( + () => ({ + search: true, + reload: onAssetsReload, + }), + [onAssetsReload], + ); - const handleToolbarEvents: ListToolBarProps | undefined = { + const toolbar: ListToolBarProps = { search: ( { - if (value) { - onSearchTerm(value); - } else { - onSearchTerm(); - } + onSearchTerm(value); }} key={+resetFlag.current} /> ), }; - const pagination: TablePaginationConfig = { - showSizeChanger: true, - current: page, - total: totalCount, - pageSize: pageSize, - }; + const pagination: TablePaginationConfig = useMemo( + () => ({ + showSizeChanger: true, + current: page, + total: totalCount, + pageSize: pageSize, + }), + [page, pageSize, totalCount], + ); const onLinkClick = useCallback( (isLink: boolean, asset: Asset) => { @@ -123,58 +127,78 @@ const LinkAssetModal: React.FC = ({ [onChange, onLinkAssetModalCancel, onSelect], ); - const columns: ProColumns[] = [ - { - title: "", - render: (_, asset) => { - const isLink = - (asset.id === linkedAsset?.id && hoveredAssetId !== asset.id) || - (asset.id !== linkedAsset?.id && hoveredAssetId === asset.id); - return ( -