@@ -5,23 +5,27 @@ import {
55 Button ,
66 Card ,
77 CopyButton ,
8+ Divider ,
89 Group ,
10+ Loader ,
911 Menu ,
1012 Stack ,
1113 Text ,
1214 Tooltip
1315} from '@mantine/core'
16+ import { TbCheck , TbChevronDown , TbCpu2 , TbDownload , TbEdit , TbEye } from 'react-icons/tb'
1417import { PiCheck , PiCopy , PiCpu , PiPencil , PiTag , PiTrashDuotone } from 'react-icons/pi'
15- import { TbChevronDown , TbDownload , TbEdit , TbEye } from 'react-icons/tb'
1618import { GetConfigProfilesCommand } from '@remnawave/backend-contract'
1719import { githubDarkTheme , JsonEditor } from 'json-edit-react'
1820import { generatePath , useNavigate } from 'react-router-dom'
21+ import { notifications } from '@mantine/notifications'
1922import { useDisclosure } from '@mantine/hooks'
2023import { useTranslation } from 'react-i18next'
2124import { modals } from '@mantine/modals'
2225import { motion } from 'framer-motion'
2326import clsx from 'clsx'
2427
28+ import { useGetComputedConfigProfile } from '@shared/api/hooks/config-profiles/config-profiles.query.hooks'
2529import { MODALS , useModalsStoreOpenWithData } from '@entities/dashboard/modal-store'
2630import { formatInt } from '@shared/utils/misc'
2731import { XrayLogo } from '@shared/ui/logos'
@@ -58,6 +62,87 @@ export function ConfigProfileCardWidget(props: IProps) {
5862 )
5963 }
6064
65+ const { refetch : refetchComputedConfigProfile , isLoading : isLoadingComputedConfigProfile } =
66+ useGetComputedConfigProfile ( {
67+ route : {
68+ uuid : configProfile . uuid
69+ }
70+ } )
71+
72+ const handleViewComputedConfigProfile = async ( ) => {
73+ notifications . show ( {
74+ id : 'view-computed-config-profile' ,
75+ loading : true ,
76+ title : t ( 'common.loading' ) ,
77+ message : t ( 'config-profile-card.widget.loading-computed-config-profile' ) ,
78+ autoClose : false ,
79+ withCloseButton : false
80+ } )
81+
82+ const computedConfigProfile = await refetchComputedConfigProfile ( )
83+
84+ if ( computedConfigProfile && computedConfigProfile . data ) {
85+ notifications . update ( {
86+ id : 'view-computed-config-profile' ,
87+ loading : false ,
88+ title : t ( 'common.success' ) ,
89+ message : t (
90+ 'config-profile-card.widget.computed-config-profile-loaded-successfully'
91+ ) ,
92+ icon : < TbCheck size = { 18 } /> ,
93+ autoClose : 3000
94+ } )
95+
96+ modals . openConfirmModal ( {
97+ children : (
98+ < >
99+ < Text size = "sm" >
100+ { t (
101+ 'config-profile-card.widget.the-computed-config-profile-description'
102+ ) }
103+ </ Text >
104+ < Divider my = "md" />
105+ < JsonEditor
106+ data = { computedConfigProfile . data . config as object }
107+ indent = { 4 }
108+ maxWidth = "100%"
109+ rootName = ""
110+ theme = { githubDarkTheme }
111+ viewOnly
112+ />
113+ </ >
114+ ) ,
115+ cancelProps : {
116+ variant : 'subtle' ,
117+ color : 'gray'
118+ } ,
119+ confirmProps : {
120+ color : 'teal'
121+ } ,
122+ labels : {
123+ confirm : t ( 'common.download' ) ,
124+ cancel : t ( 'common.cancel' )
125+ } ,
126+ size : 'xl' ,
127+ title : computedConfigProfile . data . name ,
128+ onConfirm : ( ) => {
129+ const jsonString = JSON . stringify ( computedConfigProfile . data . config , null , 2 )
130+ const blob = new Blob ( [ jsonString ] , {
131+ type : 'application/json'
132+ } )
133+ const url = URL . createObjectURL ( blob )
134+ const a = document . createElement ( 'a' )
135+ a . href = url
136+ a . download = `${ computedConfigProfile . data . name } .json`
137+ document . body . appendChild ( a )
138+ a . click ( )
139+ document . body . removeChild ( a )
140+ URL . revokeObjectURL ( url )
141+ }
142+ } )
143+ }
144+ }
145+
61146 return (
62147 < motion . div
63148 animate = { { opacity : 1 , y : 0 } }
@@ -225,6 +310,22 @@ export function ConfigProfileCardWidget(props: IProps) {
225310 { t ( 'config-profiles-grid.widget.quick-view' ) }
226311 </ Menu . Item >
227312
313+ < Menu . Item
314+ leftSection = {
315+ isLoadingComputedConfigProfile ? (
316+ < Loader size = { 18 } />
317+ ) : (
318+ < TbCpu2 size = { 18 } />
319+ )
320+ }
321+ onClick = { ( e ) => {
322+ e . stopPropagation ( )
323+ handleViewComputedConfigProfile ( )
324+ } }
325+ >
326+ { t ( 'config-profile-card.widget.view-computed' ) }
327+ </ Menu . Item >
328+
228329 < Menu . Item
229330 leftSection = { < TbDownload size = { 18 } /> }
230331 onClick = { ( e ) => {
0 commit comments