diff --git a/package.json b/package.json index 555f332d..0220dfec 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "nanostores": "^0.9.2", "prettier": "^2.8.8", "prettier-plugin-tailwindcss": "^0.3.0", + "qrcode.react": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^13.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a74c2fe5..ca673df7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -203,6 +203,9 @@ dependencies: prettier-plugin-tailwindcss: specifier: ^0.3.0 version: 0.3.0(prettier@2.8.8) + qrcode.react: + specifier: ^3.1.0 + version: 3.1.0(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -7347,6 +7350,14 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} dev: false + /qrcode.react@3.1.0(react@18.2.0): + resolution: {integrity: sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: false diff --git a/src/components/ConfigFormModal.tsx b/src/components/ConfigFormModal.tsx index 55cce7e6..52562363 100644 --- a/src/components/ConfigFormModal.tsx +++ b/src/components/ConfigFormModal.tsx @@ -122,7 +122,7 @@ const InputList = >({ ) } -export type ConfigFormDrawerRef = { +export type ConfigFormModalRef = { form: UseFormReturnType> setEditingID: (id: string) => void initOrigins: (origins: z.infer) => void diff --git a/src/components/GroupFormModal.tsx b/src/components/GroupFormModal.tsx index d3b0dc5a..9c9f1f6e 100644 --- a/src/components/GroupFormModal.tsx +++ b/src/components/GroupFormModal.tsx @@ -16,7 +16,7 @@ const schema = z.object({ policy: z.nativeEnum(Policy), }) -export type GroupFormDrawerRef = { +export type GroupFormModalRef = { form: UseFormReturnType> setEditingID: (id: string) => void initOrigins: (origins: z.infer) => void diff --git a/src/components/NodeQRCodeModal.tsx b/src/components/NodeQRCodeModal.tsx new file mode 100644 index 00000000..7b8ad0ca --- /dev/null +++ b/src/components/NodeQRCodeModal.tsx @@ -0,0 +1,33 @@ +import { Center, Modal } from '@mantine/core' +import { QRCodeSVG } from 'qrcode.react' +import { forwardRef, useImperativeHandle, useState } from 'react' + +type Props = { + name: string + link: string +} + +export type QRCodeModalRef = { + props: Props + setProps: (props: Props) => void +} + +export const QRCodeModal = forwardRef(({ opened, onClose }: { opened: boolean; onClose: () => void }, ref) => { + const [props, setProps] = useState({ + name: '', + link: '', + }) + + useImperativeHandle(ref, () => ({ + props, + setProps, + })) + + return ( + +
+ +
+
+ ) +}) diff --git a/src/pages/Orchestrate/Config.tsx b/src/pages/Orchestrate/Config.tsx index 1fbd8d67..116d5603 100644 --- a/src/pages/Orchestrate/Config.tsx +++ b/src/pages/Orchestrate/Config.tsx @@ -7,7 +7,7 @@ import { Fragment, useRef } from 'react' import { useTranslation } from 'react-i18next' import { useConfigsQuery, useRemoveConfigMutation, useSelectConfigMutation } from '~/apis' -import { ConfigFormDrawer, ConfigFormDrawerRef } from '~/components/ConfigFormModal' +import { ConfigFormDrawer, ConfigFormModalRef } from '~/components/ConfigFormModal' import { RenameFormModal, RenameFormModalRef } from '~/components/RenameFormModal' import { Section } from '~/components/Section' import { SimpleCard } from '~/components/SimpleCard' @@ -23,7 +23,7 @@ export const Config = () => { const { data: configsQuery } = useConfigsQuery() const selectConfigMutation = useSelectConfigMutation() const removeConfigMutation = useRemoveConfigMutation() - const updateConfigFormDrawerRef = useRef(null) + const updateConfigFormModalRef = useRef(null) const [openedRenameFormModal, { open: openRenameFormModal, close: closeRenameFormModal }] = useDisclosure(false) const renameFormModalRef = useRef(null) @@ -60,14 +60,14 @@ export const Config = () => { { - updateConfigFormDrawerRef.current?.setEditingID(config.id) + updateConfigFormModalRef.current?.setEditingID(config.id) const { checkInterval, checkTolerance, sniffingTimeout, logLevel, ...global } = config.global const logLevelSteps = GET_LOG_LEVEL_STEPS(t) const logLevelNumber = logLevelSteps.findIndex(([, l]) => l === logLevel) - updateConfigFormDrawerRef.current?.initOrigins({ + updateConfigFormModalRef.current?.initOrigins({ name: config.name, logLevelNumber, checkIntervalSeconds: deriveTime(checkInterval, 's'), @@ -93,7 +93,7 @@ export const Config = () => { diff --git a/src/pages/Orchestrate/Group.tsx b/src/pages/Orchestrate/Group.tsx index e0fd586d..ed08a438 100644 --- a/src/pages/Orchestrate/Group.tsx +++ b/src/pages/Orchestrate/Group.tsx @@ -14,7 +14,7 @@ import { } from '~/apis' import { DraggableResourceBadge } from '~/components/DraggableResourceBadge' import { DroppableGroupCard } from '~/components/DroppableGroupCard' -import { GroupFormDrawerRef, GroupFormModal } from '~/components/GroupFormModal' +import { GroupFormModal, GroupFormModalRef } from '~/components/GroupFormModal' import { RenameFormModal, RenameFormModalRef } from '~/components/RenameFormModal' import { Section } from '~/components/Section' import { DraggableResourceType, RuleType } from '~/constants' @@ -34,7 +34,7 @@ export const GroupResource = ({ highlight }: { highlight?: boolean }) => { const groupDelSubscriptionsMutation = useGroupDelSubscriptionsMutation() const [droppableGroupCardAccordionValues, setDroppableGroupCardAccordionValues] = useState([]) const renameFormModalRef = useRef(null) - const updateGroupFormModalRef = useRef(null) + const updateGroupFormModalRef = useRef(null) const { data: subscriptionsQuery } = useSubscriptionsQuery() return ( diff --git a/src/pages/Orchestrate/Node.tsx b/src/pages/Orchestrate/Node.tsx index 9c8acc77..79aa5848 100644 --- a/src/pages/Orchestrate/Node.tsx +++ b/src/pages/Orchestrate/Node.tsx @@ -1,11 +1,13 @@ -import { Spoiler, Text, useMantineTheme } from '@mantine/core' +import { ActionIcon, Spoiler, Text, useMantineTheme } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' -import { IconCloud } from '@tabler/icons-react' +import { IconCloud, IconDetails } from '@tabler/icons-react' +import { useRef } from 'react' import { useTranslation } from 'react-i18next' import { useImportNodesMutation, useNodesQuery, useRemoveNodesMutation } from '~/apis' import { DraggableResourceCard } from '~/components/DraggableResourceCard' import { ImportResourceFormModal } from '~/components/ImportResourceFormModal' +import { QRCodeModal, QRCodeModalRef } from '~/components/NodeQRCodeModal' import { Section } from '~/components/Section' import { DraggableResourceType } from '~/constants' @@ -13,8 +15,10 @@ export const NodeResource = () => { const { t } = useTranslation() const theme = useMantineTheme() + const [openedQRCodeModal, { open: openQRCodeModal, close: closeQRCodeModal }] = useDisclosure(false) const [openedImportNodeFormModal, { open: openImportNodeFormModal, close: closeImportNodeFormModal }] = useDisclosure(false) + const qrCodeModalRef = useRef(null) const { data: nodesQuery } = useNodesQuery() const removeNodesMutation = useRemoveNodesMutation() const importNodesMutation = useImportNodesMutation() @@ -33,9 +37,23 @@ export const NodeResource = () => { {protocol} } + actions={ + { + qrCodeModalRef.current?.setProps({ + name: name || tag!, + link, + }) + openQRCodeModal() + }} + > + + + } onRemove={() => removeNodesMutation.mutate([id])} > - + {name} @@ -56,6 +74,8 @@ export const NodeResource = () => { ))} + + { const { t } = useTranslation() + + const [openedQRCodeModal, { open: openQRCodeModal, close: closeQRCodeModal }] = useDisclosure(false) const [ openedImportSubscriptionFormModal, { open: openImportSubscriptionFormModal, close: closeImportSubscriptionFormModal }, ] = useDisclosure(false) + const qrCodeModalRef = useRef(null) const { data: subscriptionsQuery } = useSubscriptionsQuery() const removeSubscriptionsMutation = useRemoveSubscriptionsMutation() const importSubscriptionsMutation = useImportSubscriptionsMutation() @@ -55,7 +60,23 @@ export const SubscriptionResource = () => { subscriptionID={subscriptionID} type={DraggableResourceType.subscription} name={tag || link} - actions={} + actions={ + + { + qrCodeModalRef.current?.setProps({ + name: tag!, + link, + }) + openQRCodeModal() + }} + > + + + + + } onRemove={() => removeSubscriptionsMutation.mutate([subscriptionID])} > {dayjs(updatedAt).format('YYYY-MM-DD HH:mm:ss')} @@ -101,6 +122,8 @@ export const SubscriptionResource = () => { ))} + +