Skip to content

Commit

Permalink
✨ Implement the table item dropdown menu (#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
tosone authored Jun 26, 2024
1 parent 2eb79f4 commit 258bffd
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 70 deletions.
3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@tailwindcss/typography": "^0.5.13",
"axios": "^1.7.2",
"bytemd": "^1.21.0",
"clsx": "^2.1.1",
"cron-parser": "^4.9.0",
"csstype": "^3.1.3",
"dayjs": "^1.11.11",
Expand Down Expand Up @@ -56,5 +57,5 @@
"typescript": "^5.4.5",
"vite": "^5.2.13"
},
"packageManager": "yarn@4.2.1"
"packageManager": "yarn@4.3.1"
}
19 changes: 19 additions & 0 deletions web/src/components/Menu/TableItemDropdown/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright 2024 sigma
*
* 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.
*/

.menu-action-top {
margin-top: -7rem;
}
71 changes: 71 additions & 0 deletions web/src/components/Menu/TableItemDropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Copyright 2024 sigma
*
* 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 "./index.css";

import clsx from 'clsx';
import { Fragment } from 'react';
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";

interface ITableItemDropdownProps {
index?: number;
items?: ITableItemDropdownItem[];
}

interface ITableItemDropdownItem {
name: string;
onClick: () => void;
warn?: boolean;
disable?: boolean;
}

export default function ({ index, items }: ITableItemDropdownProps) {
return items && items.length > 0 && !items.every(item => item.disable) ? (
<Menu as="div" className="relative flex-none" onClick={e => e.stopPropagation()}>
<MenuButton className="mx-auto -m-2.5 block p-2.5 text-gray-500 hover:text-gray-900 margin">
<span className="sr-only">Open options</span>
<EllipsisVerticalIcon className="h-5 w-5" aria-hidden="true" />
</MenuButton>
<MenuItems
className={clsx(
index || 0 > 10 ? "menu-action-top" : "mt-2",
" text-left absolute right-0 z-10 w-20 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none")
}
>
{
items.map((item, index) => (
item.disable ? null :
<MenuItem as={Fragment} key={index}>
{({ focus }) => (
<div
className={clsx(
focus ? 'bg-gray-100' : '',
'block px-4 py-1.5 text-sm leading-6 text-gray-900 cursor-pointer',
item.warn ? 'hover:text-white hover:bg-red-600' : ''
)}
onClick={item.onClick}
>
{item.name}
</div>
)}
</MenuItem>
))
}
</MenuItems>
</Menu >
) : null;
}
1 change: 0 additions & 1 deletion web/src/pages/DaemonTask/Tasks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { Tooltip } from 'flowbite';
import Header from "../../components/Header";
import IMenu from "../../components/Menu";
import Notification from "../../components/Notification";
import Settings from "../../Settings";
import {
IGcArtifactRule,
IGcArtifactRunnerItem,
Expand Down
4 changes: 2 additions & 2 deletions web/src/pages/Login/Callback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

import "./index.css";

import { IHTTPError, IUserLoginResponse, IUserSelf } from "../../interfaces";
import axios from "axios";
import { useEffect, useState } from "react";
import { useParams, useSearchParams } from "react-router-dom";

import { IHTTPError, IUserLoginResponse, IUserSelf } from "../../interfaces";
import Toast from "../../components/Notification";
import axios from "axios";

export default function ({ localServer }: { localServer: string }) {
const { provider } = useParams<{ provider: string }>();
Expand Down
78 changes: 22 additions & 56 deletions web/src/pages/Repository/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import "./index.css";

import axios from "axios";
import dayjs from "dayjs";
import { Dialog, DialogPanel, DialogTitle, Menu, MenuButton, MenuItem, MenuItems, Transition, TransitionChild } from "@headlessui/react";
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
import { useDebounce } from "react-use";
import { Fragment, useEffect, useState } from "react";
import { Helmet, HelmetProvider } from 'react-helmet-async';
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { useDebounce } from "react-use";
import { Dialog, DialogPanel, DialogTitle, Menu, MenuButton, MenuItem, MenuItems, Transition, TransitionChild } from "@headlessui/react";

import Header from "../../components/Header";
import IMenu from "../../components/Menu";
Expand All @@ -38,6 +38,7 @@ import Toast from "../../components/Notification";
import calcUnit from "../../utils/calcUnit";
import { IHTTPError, INamespaceItem, IOrder, IRepositoryItem, IRepositoryList, IUserSelf } from "../../interfaces";
import { NamespaceRole, UserRole } from "../../interfaces/enums";
import TableItemDropdown from "../../components/Menu/TableItemDropdown";

export default function ({ localServer }: { localServer: string }) {
const [repositoryList, setRepositoryList] = useState<IRepositoryList>({} as IRepositoryList);
Expand Down Expand Up @@ -661,58 +662,23 @@ function TableItem({ localServer, index, user, namespace, repository, setRefresh
{dayjs.utc(repository.updated_at).tz(dayjs.tz.guess()).format("YYYY-MM-DD HH:mm:ss")}
</td>
<td className="pr-3 whitespace-nowrap">
<Menu as="div" className="relative flex-none" onClick={e => {
e.stopPropagation();
}}>
<MenuButton className="mx-auto -m-2.5 block p-2.5 text-gray-500 hover:text-gray-900 margin">
<span className="sr-only">Open options</span>
<EllipsisVerticalIcon className="h-5 w-5" aria-hidden="true" />
</MenuButton>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<MenuItems className={(index > 10 ? "menu-action-top" : "mt-2") + " text-left absolute right-0 z-10 w-20 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none"} >
<MenuItem>
{({ active }) => (
<div
className={
(active ? 'bg-gray-100' : '') +
(((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))) ? ' cursor-pointer ' : ' cursor-not-allowed ') +
' block px-3 py-1 text-sm leading-6 text-gray-900 cursor-pointer'
}
onClick={e => {
((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))) && setUpdateRepositoryModal(true);
}}
>
Update
</div>
)}
</MenuItem>
<MenuItem>
{({ active }) => (
<div
className={
(active ? 'bg-gray-50' : '') +
(((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))) ? ' cursor-pointer' : ' cursor-not-allowed') +
' block px-3 py-1 text-sm leading-6 text-gray-900 hover:text-white hover:bg-red-600 cursor-pointer'
}
onClick={e => {
((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))) && setDeleteRepositoryModal(true);
}}
>
Delete
</div>
)}
</MenuItem>
</MenuItems>
</Transition>
</Menu>
<TableItemDropdown index={index}
items={
[
{
name: "Update",
disable: !((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))),
onClick: () => { setUpdateRepositoryModal(true) },
},
{
name: "Delete",
disable: !((user.role == UserRole.Admin || user.role == UserRole.Root || (namespace.role != undefined && (namespace.role == NamespaceRole.Admin || namespace.role == NamespaceRole.Manager)))),
warn: true,
onClick: () => { setDeleteRepositoryModal(true) },
},
]
}
/>
</td>
<td>
<Transition show={updateRepositoryModal} as={Fragment}>
Expand Down
18 changes: 9 additions & 9 deletions web/src/pages/Tag/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import axios from "axios";
import dayjs from 'dayjs';
import humanFormat from "human-format";
import { Dialog, Menu, Transition } from "@headlessui/react";
import { Dialog, DialogTitle, Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react";
import { EllipsisVerticalIcon } from '@heroicons/react/20/solid';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
import { Fragment, useEffect, useState } from "react";
Expand Down Expand Up @@ -289,9 +289,9 @@ export default function Tag({ localServer }: { localServer: string }) {
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<Dialog.Title as="h3" className="text-base font-semibold leading-6 text-gray-900">
<DialogTitle as="h3" className="text-base font-semibold leading-6 text-gray-900">
Delete tag
</Dialog.Title>
</DialogTitle>
<div className="mt-2">
<p className="text-sm text-gray-500">
Are you sure you want to delete the tag <span className="text-black font-medium">{deleteTagModalTag.name}</span>
Expand Down Expand Up @@ -372,10 +372,10 @@ export default function Tag({ localServer }: { localServer: string }) {
<Menu as="div" className="relative flex-none" onClick={e => {
e.stopPropagation();
}}>
<Menu.Button className="mx-auto my-auto block p-1 text-gray-500 hover:text-gray-900 margin">
<MenuButton className="mx-auto my-auto block p-1 text-gray-500 hover:text-gray-900 margin">
<span className="sr-only">Open options</span>
<EllipsisVerticalIcon className="h-5 w-5" aria-hidden="true" />
</Menu.Button>
</MenuButton>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
Expand All @@ -385,8 +385,8 @@ export default function Tag({ localServer }: { localServer: string }) {
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className={(index > 10 ? "menu-action-top" : "mt-2") + " text-left absolute right-0 z-10 w-20 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none"} >
<Menu.Item>
<MenuItems className={(index > 10 ? "menu-action-top" : "mt-2") + " text-left absolute right-0 z-10 w-20 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none"} >
<MenuItem>
{({ active }) => (
<div
className={
Expand All @@ -402,8 +402,8 @@ export default function Tag({ localServer }: { localServer: string }) {
Delete
</div>
)}
</Menu.Item>
</Menu.Items>
</MenuItem>
</MenuItems>
</Transition>
</Menu>
</div>
Expand Down
3 changes: 2 additions & 1 deletion web/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@ __metadata:
languageName: node
linkType: hard

"clsx@npm:^2.0.0":
"clsx@npm:^2.0.0, clsx@npm:^2.1.1":
version: 2.1.1
resolution: "clsx@npm:2.1.1"
checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839
Expand Down Expand Up @@ -4710,6 +4710,7 @@ __metadata:
autoprefixer: "npm:^10.4.19"
axios: "npm:^1.7.2"
bytemd: "npm:^1.21.0"
clsx: "npm:^2.1.1"
cron-parser: "npm:^4.9.0"
cssnano: "npm:^7.0.2"
csstype: "npm:^3.1.3"
Expand Down

0 comments on commit 258bffd

Please sign in to comment.