Skip to content

Commit cfe874b

Browse files
committed
feat: add subpage config tab to external squads
1 parent eb0794d commit cfe874b

File tree

8 files changed

+168
-18
lines changed

8 files changed

+168
-18
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
"@monaco-editor/react": "^4.7.0",
6060
"@noble/post-quantum": "^0.5.2",
6161
"@paralleldrive/cuid2": "2.2.2",
62-
"@remnawave/backend-contract": "2.3.55",
63-
"@remnawave/subscription-page-types": "0.0.6",
62+
"@remnawave/backend-contract": "2.3.59",
63+
"@remnawave/subscription-page-types": "0.1.0",
6464
"@simplewebauthn/browser": "^13.2.2",
6565
"@stablelib/base64": "^2.0.1",
6666
"@stablelib/x25519": "^2.0.1",

public/locales/en/remnawave.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,5 +1815,15 @@
18151815
"svg-code": "SVG Code",
18161816
"preview": "Preview"
18171817
}
1818+
},
1819+
"external-squads-subpage-config": {
1820+
"tab": {
1821+
"widget": {
1822+
"subscription-page-config": "Subscription Page Config",
1823+
"subscription-page-config-description": "You can override the subscription page configuration (Remnawave Subscription Page) for this external squad.",
1824+
"subpage-config": "Subpage Config",
1825+
"select-config": "Select config..."
1826+
}
1827+
}
18181828
}
18191829
}

src/pages/dashboard/external-squads/connectors/external-squads.page.connector.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
import { useGetExternalSquads, useGetSubscriptionTemplates } from '@shared/api/hooks'
1+
import {
2+
useGetExternalSquads,
3+
useGetSubscriptionPageConfigs,
4+
useGetSubscriptionTemplates
5+
} from '@shared/api/hooks'
26
import { LoadingScreen } from '@shared/ui'
37

48
import { ExternalSquadsPageComponent } from '../components/external-squads.page.component'
59

610
export function ExternalSquadsPageConnector() {
711
const { data: externalSquads, isLoading: isExternalSquadsLoading } = useGetExternalSquads()
812
const { isLoading: isTemplatesLoading } = useGetSubscriptionTemplates()
13+
const { isLoading: isSubscriptionPageConfigsLoading } = useGetSubscriptionPageConfigs()
914

10-
if (isExternalSquadsLoading || !externalSquads || isTemplatesLoading) {
15+
if (
16+
isExternalSquadsLoading ||
17+
!externalSquads ||
18+
isTemplatesLoading ||
19+
isSubscriptionPageConfigsLoading
20+
) {
1121
return <LoadingScreen />
1222
}
1323
return <ExternalSquadsPageComponent externalSquads={externalSquads.externalSquads} />

src/shared/api/hooks/subpage-configs/subpage-configs.query.hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const useGetSubscriptionPageConfigs = createGetQueryHook({
3535
getQueryKey: () => subpageConfigsQueryKeys.getSubscriptionPageConfigs.queryKey,
3636
rQueryParams: {
3737
refetchOnMount: false,
38-
staleTime: sToMs(30)
38+
staleTime: sToMs(15)
3939
},
4040
errorHandler: (error) => errorHandler(error, 'Get Subscription Page Configs')
4141
})

src/widgets/dashboard/external-squads/external-squads-drawer/external-squads.drawer.widget.tsx

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,32 @@ import {
1313
Tooltip,
1414
Transition
1515
} from '@mantine/core'
16-
import { TbFolder, TbListLetters, TbPrescription, TbSettings, TbWebhook } from 'react-icons/tb'
16+
import {
17+
TbFolder,
18+
TbListLetters,
19+
TbPalette,
20+
TbPrescription,
21+
TbSettings,
22+
TbWebhook
23+
} from 'react-icons/tb'
1724
import { PiCheck, PiCopy, PiIdentificationBadge, PiListChecks, PiUsers } from 'react-icons/pi'
1825
import { useTranslation } from 'react-i18next'
1926
import { memo, useState } from 'react'
2027

28+
import {
29+
useGetExternalSquad,
30+
useGetSubscriptionPageConfigs,
31+
useGetSubscriptionTemplates
32+
} from '@shared/api/hooks'
2133
import { MODALS, useModalClose, useModalState } from '@entities/dashboard/modal-store'
22-
import { useGetExternalSquad, useGetSubscriptionTemplates } from '@shared/api/hooks'
2334
import { LoaderModalShared } from '@shared/ui/loader-modal'
2435
import { formatInt } from '@shared/utils/misc'
2536

2637
import {
2738
ExternalSquadsHostOverridesTabWidget,
2839
ExternalSquadsHwidSettingsTabWidget,
2940
ExternalSquadsSettingsTabWidget,
41+
ExternalSquadsSubpageConfigTabWidget,
3042
ExternalSquadsTemplatesTabWidget
3143
} from './tabs'
3244
import { ExternalSquadsResponseHeadersTabWidget } from './tabs/external-squads-response-headers.widget'
@@ -39,7 +51,8 @@ const TAB_TYPE = {
3951
hosts: 'hosts',
4052
responseHeaders: 'responseHeaders',
4153
hwidSettings: 'hwidSettings',
42-
customRemarks: 'customRemarks'
54+
customRemarks: 'customRemarks',
55+
subpageConfig: 'subpageConfig'
4356
} as const
4457

4558
type TabType = (typeof TAB_TYPE)[keyof typeof TAB_TYPE]
@@ -54,6 +67,7 @@ export const ExternalSquadsDrawer = memo(() => {
5467
const close = useModalClose(MODALS.EXTERNAL_SQUAD_DRAWER)
5568

5669
const { isLoading: isTemplatesLoading } = useGetSubscriptionTemplates()
70+
const { isLoading: isSubpageConfigsLoading } = useGetSubscriptionPageConfigs()
5771

5872
const { data: externalSquad, isLoading: isExternalSquadLoading } = useGetExternalSquad({
5973
route: {
@@ -200,6 +214,12 @@ export const ExternalSquadsDrawer = memo(() => {
200214
>
201215
{t('external-squads.drawer.widget.remarks')}
202216
</Tabs.Tab>
217+
<Tabs.Tab
218+
leftSection={<TbPalette size={px('1.2rem')} />}
219+
value={TAB_TYPE.subpageConfig}
220+
>
221+
{t('constants.subscription-page')}
222+
</Tabs.Tab>
203223
</Tabs.List>
204224

205225
<Tabs.Panel pt="xl" value={TAB_TYPE.templates}>
@@ -309,12 +329,29 @@ export const ExternalSquadsDrawer = memo(() => {
309329
)}
310330
</Transition>
311331
</Tabs.Panel>
332+
333+
<Tabs.Panel pt="xl" value={TAB_TYPE.subpageConfig}>
334+
<Transition
335+
duration={200}
336+
mounted={activeTab === TAB_TYPE.subpageConfig}
337+
timingFunction="linear"
338+
transition="fade"
339+
>
340+
{(styles) => (
341+
<Stack gap="lg" style={styles}>
342+
<ExternalSquadsSubpageConfigTabWidget
343+
externalSquad={externalSquad}
344+
/>
345+
</Stack>
346+
)}
347+
</Transition>
348+
</Tabs.Panel>
312349
</Tabs>
313350
</Stack>
314351
)
315352
}
316353

317-
const isLoading = isTemplatesLoading || isExternalSquadLoading
354+
const isLoading = isTemplatesLoading || isExternalSquadLoading || isSubpageConfigsLoading
318355

319356
return (
320357
<Drawer
@@ -324,7 +361,7 @@ export const ExternalSquadsDrawer = memo(() => {
324361
overlayProps={{ backgroundOpacity: 0.6, blur: 0 }}
325362
padding="md"
326363
position="right"
327-
size="540px"
364+
size="600px"
328365
title={t('external-squads.drawer.widget.edit-external-squad')}
329366
>
330367
<Transition
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { GetExternalSquadByUuidCommand } from '@remnawave/backend-contract'
2+
import { Button, Paper, Select, Stack, Text } from '@mantine/core'
3+
import { IconPalette } from '@tabler/icons-react'
4+
import { TbDeviceFloppy } from 'react-icons/tb'
5+
import { useTranslation } from 'react-i18next'
6+
import { useState } from 'react'
7+
8+
import { QueryKeys, useGetSubscriptionPageConfigs, useUpdateExternalSquad } from '@shared/api/hooks'
9+
import { queryClient } from '@shared/api'
10+
11+
interface IProps {
12+
externalSquad: GetExternalSquadByUuidCommand.Response['response']
13+
}
14+
15+
export const ExternalSquadsSubpageConfigTabWidget = (props: IProps) => {
16+
const { externalSquad } = props
17+
const { t } = useTranslation()
18+
19+
const { data: subpageConfigs } = useGetSubscriptionPageConfigs()
20+
21+
const [selectedConfigUuid, setSelectedConfigUuid] = useState<null | string>(
22+
externalSquad.subpageConfigUuid || null
23+
)
24+
25+
const { mutate: updateExternalSquad, isPending: isUpdatingExternalSquad } =
26+
useUpdateExternalSquad({
27+
mutationFns: {
28+
onSuccess: (data) => {
29+
queryClient.setQueryData(
30+
QueryKeys.externalSquads.getExternalSquad({
31+
uuid: data.uuid
32+
}).queryKey,
33+
data
34+
)
35+
}
36+
}
37+
})
38+
39+
const handleSave = () => {
40+
if (!externalSquad?.uuid) return
41+
42+
updateExternalSquad({
43+
variables: {
44+
subpageConfigUuid: selectedConfigUuid,
45+
uuid: externalSquad.uuid
46+
}
47+
})
48+
}
49+
50+
const configOptions =
51+
subpageConfigs?.configs.map((config) => ({
52+
label: config.name,
53+
value: config.uuid
54+
})) || []
55+
56+
return (
57+
<Paper bg="dark.6" p="md" shadow="sm" withBorder>
58+
<Stack gap="md">
59+
<Text fw={600} size="md">
60+
{t('external-squads-subpage-config.tab.widget.subscription-page-config')}
61+
</Text>
62+
<Text c="dimmed" size="sm">
63+
{t(
64+
'external-squads-subpage-config.tab.widget.subscription-page-config-description'
65+
)}
66+
</Text>
67+
68+
<Select
69+
clearable
70+
data={configOptions}
71+
label={t('external-squads-subpage-config.tab.widget.subpage-config')}
72+
leftSection={<IconPalette size={16} />}
73+
onChange={setSelectedConfigUuid}
74+
placeholder={t('external-squads-subpage-config.tab.widget.select-config')}
75+
value={selectedConfigUuid}
76+
/>
77+
78+
<Button
79+
color="teal"
80+
fullWidth
81+
leftSection={<TbDeviceFloppy size="1.2rem" />}
82+
loading={isUpdatingExternalSquad}
83+
onClick={handleSave}
84+
size="md"
85+
variant="light"
86+
>
87+
{t('common.save')}
88+
</Button>
89+
</Stack>
90+
</Paper>
91+
)
92+
}

src/widgets/dashboard/external-squads/external-squads-drawer/tabs/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export * from './external-squad-overrides-tab.widget'
22
export * from './external-squads-hosts.tab.widget'
33
export * from './external-squads-hwid-settings.tab.widget'
44
export * from './external-squads-settings.tab.widget'
5+
export * from './external-squads-subpage-config.tab.widget'
56
export * from './external-squads-templates.tab.widget'

0 commit comments

Comments
 (0)