diff --git a/moon/apps/web/components/Issues/IssueSearch.tsx b/moon/apps/web/components/Issues/IssueSearch.tsx index ccf81c5eb..0f1538902 100644 --- a/moon/apps/web/components/Issues/IssueSearch.tsx +++ b/moon/apps/web/components/Issues/IssueSearch.tsx @@ -38,9 +38,7 @@ export default function IssueSearch() { }} /> {/* */} - + @@ -58,3 +56,15 @@ export const NewIssueButton = () => { ) } + +const LabelsButton = () => { + const { scope } = useScope() + + return ( + + + + ) +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/utils/store.tsx b/moon/apps/web/components/Issues/utils/store.tsx index f5c3edb8c..a15dee0ad 100644 --- a/moon/apps/web/components/Issues/utils/store.tsx +++ b/moon/apps/web/components/Issues/utils/store.tsx @@ -35,4 +35,7 @@ export const issueOpenCurrentPage = atomWithWebStorage('IssueOpencurrentPage', 1 export const issueCloseCurrentPage = atomWithWebStorage('IssueClosecurrentPage', 1) export const mrOpenCurrentPage = atomWithWebStorage('MROpencurrentPage', 1) -export const mrCloseCurrentPage = atomWithWebStorage('MRClosecurrentPage', 1) \ No newline at end of file +export const mrCloseCurrentPage = atomWithWebStorage('MRClosecurrentPage', 1) + +export const labelsOpenCurrentPage = atomWithWebStorage('LabelsOpenCurrentPage', 1) +export const labelsCloseCurrentPage = atomWithWebStorage('LabelsCloseCurrentPage', 1) \ No newline at end of file diff --git a/moon/apps/web/hooks/usePostLabelList.ts b/moon/apps/web/hooks/usePostLabelList.ts new file mode 100644 index 000000000..fdbb3b5dc --- /dev/null +++ b/moon/apps/web/hooks/usePostLabelList.ts @@ -0,0 +1,10 @@ +// hooks/usePostLabelList.ts +import { PageParamsString, PostApiLabelListData, RequestParams } from '@gitmono/types' +import { legacyApiClient } from '@/utils/queryClient' +import { useMutation } from '@tanstack/react-query' + +export function usePostLabelList() { + return useMutation({ + mutationFn: ({ data, params }) => legacyApiClient.v1.postApiLabelList().request(data, params) + }) +} \ No newline at end of file diff --git a/moon/apps/web/package.json b/moon/apps/web/package.json index e65e38edd..70928a651 100644 --- a/moon/apps/web/package.json +++ b/moon/apps/web/package.json @@ -61,6 +61,7 @@ "@vercel/og": "catalog:", "@vercel/speed-insights": "catalog:", "clsx": "catalog:", + "colord": "catalog:", "cookies-next": "catalog:", "copy-to-clipboard": "catalog:", "d3-selection": "catalog:", diff --git a/moon/apps/web/pages/[org]/labels/index.tsx b/moon/apps/web/pages/[org]/labels/index.tsx new file mode 100644 index 000000000..530319fa1 --- /dev/null +++ b/moon/apps/web/pages/[org]/labels/index.tsx @@ -0,0 +1,196 @@ +import React, { AwaitedReactNode, JSX, ReactElement, ReactNode, ReactPortal, useCallback, useEffect, useState } from 'react' +import { colord } from 'colord' +import { useRouter } from 'next/router' +import { useDebounce } from 'use-debounce' + +import { PostApiLabelListData } from '@gitmono/types' +import {Button, cn, LazyLoadingSpinner, SearchIcon} from '@gitmono/ui' + +import { IndexPageContainer, IndexPageContent } from '@/components/IndexPages/components' +import { IssueList as LabelList, ListItem } from '@/components/Issues/IssueList' +import { Pagination } from '@/components/Issues/Pagenation' +import { labelsOpenCurrentPage } from '@/components/Issues/utils/store' +import { AppLayout } from '@/components/Layout/AppLayout' +import { Heading } from '@/components/MrView/catalyst/heading' +import AuthAppProviders from '@/components/Providers/AuthAppProviders' +import { BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar' +import { useScope } from '@/contexts/scope' +import { usePostLabelList } from '@/hooks/usePostLabelList' +import { apiErrorToast } from '@/utils/apiErrorToast' + +type ItemsType = NonNullable['items'] + +function LabelsPage() { + const router = useRouter() + const { scope } = useScope() + + const [query, setQuery] = useState("") + const [queryDebounced] = useDebounce(query, 150) + const [isLoading, setIsLoading] = useState(false) + const [isSearchLoading, setIsSearchLoading] = useState(false) + + const handleQuery = () => { + setIsSearchLoading(true) + setShowLabelList( + () => + labelList.filter((i) => + i.name.toLowerCase().includes(queryDebounced.toLowerCase()))) + setIsSearchLoading(false) + } + + const [labelList, setLabelList] = useState([]) + const [showLabelList, setShowLabelList] = useState([]) + const [numTotal, setNumTotal] = useState(0) + const [page, setPage] = useState(1) + const [per_page] = useState(20) + const { mutate: fetchLabelList } = usePostLabelList() + const fetchLabels = useCallback(() => { + setIsLoading(true) + + fetchLabelList( + { + data: { + additional: 'string', + pagination: { + page, + per_page + } + } + }, + { + onSuccess: (response) => { + const data = response.data + + setLabelList(data?.items ?? []) + setShowLabelList(data?.items ?? []) + setNumTotal(data?.total ?? 0) + }, + onError: apiErrorToast, + onSettled: () => setIsLoading(false) + } + ) + }, [page, per_page, fetchLabelList]) + + useEffect(() => { + fetchLabels() + }, [fetchLabels]) + + return ( + <> +
+ Labels +
+ + + + +
+ { + setQuery(e.target.value) + }} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + e.stopPropagation() + handleQuery() + } + }} + /> + +
+ +
+
+
+
+ + {numTotal} labels + + } + > + {(labels) => { + return labels.map((label) => { + const fontColor = colord(label.color).lighten(0.5).toHex() + + return ( + router.push(`/${scope}/issue?q=label:${label.name}`)} + > +
+
+ {label.name} +
+
+ description: {label.description} +
+
+
+ ) + }) + }} +
+ {numTotal > per_page && ( + + )} +
+
+
+ + ) +} + +LabelsPage.getProviders = ( + page: + | string + | number + | boolean + | ReactElement + | Iterable + | ReactPortal + | Promise + | null + | undefined, + pageProps: JSX.IntrinsicAttributes & { children?: ReactNode } +) => { + return ( + + {page} + + ) +} + +export default LabelsPage diff --git a/moon/pnpm-lock.yaml b/moon/pnpm-lock.yaml index b80abd68f..8783f2730 100644 --- a/moon/pnpm-lock.yaml +++ b/moon/pnpm-lock.yaml @@ -198,6 +198,9 @@ catalogs: clsx: specifier: ^2.1.1 version: 2.1.1 + colord: + specifier: ^2.9.3 + version: 2.9.3 cookies-next: specifier: ^2.1.1 version: 2.1.1 @@ -671,6 +674,9 @@ importers: clsx: specifier: 'catalog:' version: 2.1.1 + colord: + specifier: 'catalog:' + version: 2.9.3 cookies-next: specifier: 'catalog:' version: 2.1.1 @@ -3147,6 +3153,7 @@ packages: '@playwright/test@1.43.1': resolution: {integrity: sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==} engines: {node: '>=16'} + deprecated: Please update to the latest version of Playwright to test up-to-date browsers. hasBin: true '@pmmmwh/react-refresh-webpack-plugin@0.5.11': @@ -4642,6 +4649,7 @@ packages: '@shopify/react-shortcuts@5.2.0': resolution: {integrity: sha512-qhhGvYyQG1R0+YdUPoXZzxjmMOt7SjxoM/KwEqKIf5LT2tRYsYrncrXuyhLYLYt/WpVK/e0+C6p0cEqNtLipxA==} engines: {node: '>=18.12.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. peerDependencies: react: '>=18.0.0 <19.0.0' @@ -5798,6 +5806,7 @@ packages: abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -5815,6 +5824,7 @@ packages: acorn-import-assertions@1.9.0: resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + deprecated: package has been renamed to acorn-import-attributes peerDependencies: acorn: ^8 @@ -5939,6 +5949,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6441,6 +6452,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -6922,6 +6936,7 @@ packages: domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} @@ -7538,6 +7553,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -7632,9 +7648,11 @@ packages: glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -7942,6 +7960,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -8495,6 +8514,7 @@ packages: lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. lodash.isobject@3.0.2: resolution: {integrity: sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==} @@ -9024,6 +9044,7 @@ packages: node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -9096,6 +9117,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -10236,10 +10258,12 @@ packages: rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true ripemd160@2.0.2: @@ -18286,6 +18310,8 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + colord@2.9.3: {} + colorette@2.0.20: {} combined-stream@1.0.8: diff --git a/moon/pnpm-workspace.yaml b/moon/pnpm-workspace.yaml index 01cd4cc5b..cb5ff1fe0 100644 --- a/moon/pnpm-workspace.yaml +++ b/moon/pnpm-workspace.yaml @@ -269,4 +269,5 @@ catalog: '@mui/x-tree-view': ^8.5.0 '@emotion/styled': ^11.14.0 prism-react-renderer: ^2.4.1 - material-file-icons: ^2.4.0 \ No newline at end of file + material-file-icons: ^2.4.0 + colord: ^2.9.3