@samitouri / QOSami-HFS / commits / 51e61312

admin/options/config: replaced "copy" button with "export"

Massimo Melina committed Apr 9, 2025 at 23:59 UTC 51e6131212f213d62ecfca670ba09090c5ea78ed
2 files changed +17 -8
admin/src/ConfigFilePage.ts
+5 -7
@@ -3,13 +3,12 @@
3 import { createElement as h, Fragment, useEffect, useState } from 'react';
4 import { apiCall, useApiEx } from './api'
5 import { Alert, Box } from '@mui/material'
6 -import { copyTextToClipboard, focusSelector, isCtrlKey, KeepInScreen, md } from './misc'
6 +import { downloadFileWithContent, focusSelector, isCtrlKey, KeepInScreen } from './misc'
7 import { Btn, Flex, IconBtn, reloadBtn } from './mui';
8 -import { Save, ContentCopy, Edit } from '@mui/icons-material'
8 +import { Save, Edit, Download } from '@mui/icons-material'
9 import { TextEditor } from './TextEditor';
10 import { state } from './state';
11 import { DisplayField } from '@hfs/mui-grid-form'
12 -import { toast } from './dialog';
12
13 export default function ConfigFilePage() {
14 state.title = "Config file"
@@ -21,7 +20,7 @@ export default function ConfigFilePage() {
20 useEffect(() => { saved !== undefined && setText(saved || '') }, [saved])
21 return h(Fragment, {},
22 h(Flex, { flexWrap: 'wrap', justifyContent: 'space-between' },
24 - h(Btn, { icon: ContentCopy, onClick: copy }, "Copy without passwords"),
23 + h(Btn, { icon: Download, onClick: exportConfig }, "Export without passwords"),
24 edit ? h(Fragment, {},
25 reloadBtn(reload),
26 h(IconBtn, {
@@ -60,13 +59,12 @@ export default function ConfigFilePage() {
59 return apiCall('set_config_text', { text }).then(() => setSaved(text))
60 }
61
63 - function copy() {
62 + function exportConfig() {
63 const s = (text || '')
64 .replace(/^(\s*(\w*password(?!_change)\w*|srp):\s*).+\n/gm, '$1removed\n')
65 .replace(/(:\/\/)[^/@\s]+@/g, '$1removed@')
66 + 'custom_html: | # this is currently ignored by hfs, just here for reference\n' + data.customHtml.replace(/^/gm, ' ')
67 if (!s) return
69 - copyTextToClipboard(s)
70 - toast(md`Copied!\ncustom.html included`)
68 + downloadFileWithContent('config_no_passwords.yaml', s)
69 }
70 }
shared/index.ts
+12 -1
@@ -190,7 +190,18 @@ export function copyTextToClipboard(text: string) {
190 d.body.removeChild(ta)
191 }
192
193 +export function downloadFileWithContent(name: string, content: Blob | string) {
194 + const blob = content instanceof Blob ? content : new Blob([content], {type: 'text/plain'})
195 + const a = document.createElement('a')
196 + a.href = URL.createObjectURL(blob)
197 + a.download = name
198 + a.style.display = 'none'
199 + document.body.append(a)
200 + a.click()
201 + setTimeout(() => a.remove(), 100) // Chrome needs this timeout
202 +}
203 +
204 Element.prototype.replaceChildren ||= function(this:Element, addNodes) { // polyfill
194 - while (this.lastChild) this.removeChild(this.lastChild);
205 + while (this.lastChild) this.removeChild(this.lastChild)
206 if (addNodes !== undefined) this.append(addNodes);
207 }