feat: add ability to configure application with a config file (#740)

* add config file possibility

* revert port in docker compose

* Update docker-compose.yml

Co-authored-by: Elias Schneider <login@eliasschneider.com>

* Update docker-compose.yml

Co-authored-by: Elias Schneider <login@eliasschneider.com>

* add attribute description to config file

* remove email message config

* add package to resolve errors

* remove email messages from config

* move config initialization to config module

* revert unnecessary change

* add order

* improve alert

* run formatter

* remove unnecessary packages

* remove unnecessary types

* use logger

* don't save yaml config to db

* allowEdit if no yaml config is set

* improve docs

* fix allow edit state

* remove unnecessary check and refactor code

* restore old config file

* add script that generates `config.example.yaml` automatically

* allow config variables to be changed if they are not set in the `config.yml`

* add back init user

* Revert "allow config variables to be changed if they are not set in the `config.yml`"

This reverts commit 7dbdb6729034be5b083f126f854d5e1411735a54.

* improve info box text

---------

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Mattia Müggler
2025-02-28 11:01:54 +01:00
committed by GitHub
parent f4291421b5
commit 9dfb52a145
21 changed files with 2716 additions and 2077 deletions

View File

@@ -45,6 +45,7 @@ const AdminConfigInput = ({
style={{
width: "100%",
}}
disabled={!configVariable.allowEdit}
{...form.getInputProps("stringValue")}
onChange={(e) => onValueChange(configVariable, e.target.value)}
/>
@@ -53,6 +54,7 @@ const AdminConfigInput = ({
style={{
width: "100%",
}}
disabled={!configVariable.allowEdit}
{...form.getInputProps("stringValue")}
placeholder={configVariable.defaultValue}
onChange={(e) => onValueChange(configVariable, e.target.value)}
@@ -64,6 +66,7 @@ const AdminConfigInput = ({
style={{
width: "100%",
}}
disabled={!configVariable.allowEdit}
autosize
{...form.getInputProps("textValue")}
placeholder={configVariable.defaultValue}
@@ -73,6 +76,7 @@ const AdminConfigInput = ({
{configVariable.type == "number" && (
<NumberInput
{...form.getInputProps("numberValue")}
disabled={!configVariable.allowEdit}
placeholder={configVariable.defaultValue}
onChange={(number) => onValueChange(configVariable, number)}
w={201}
@@ -81,6 +85,7 @@ const AdminConfigInput = ({
{configVariable.type == "filesize" && (
<FileSizeInput
{...form.getInputProps("numberValue")}
disabled={!configVariable.allowEdit}
value={parseInt(configVariable.value ?? configVariable.defaultValue)}
onChange={(bytes) => onValueChange(configVariable, bytes)}
w={201}
@@ -89,6 +94,7 @@ const AdminConfigInput = ({
{configVariable.type == "boolean" && (
<>
<Switch
disabled={!configVariable.allowEdit}
{...form.getInputProps("booleanValue", { type: "checkbox" })}
onChange={(e) => onValueChange(configVariable, e.target.checked)}
/>
@@ -97,6 +103,7 @@ const AdminConfigInput = ({
{configVariable.type == "timespan" && (
<TimespanInput
value={stringToTimespan(configVariable.value)}
disabled={!configVariable.allowEdit}
onChange={(timespan) =>
onValueChange(configVariable, timespanToString(timespan))
}

View File

@@ -302,6 +302,8 @@ export default {
"privacy.title": "Datenschutzerklärung",
// END /privacy
// /admin/config
"admin.config.config-file-warning.title": "Konfigurationsdatei aktiv",
"admin.config.config-file-warning.description": "Da Pingvin Share mit einer Konfigurationsdatei konfiguriert ist, kann die Konfiguration nicht über die Benutzeroberfläche geändert werden.",
"admin.config.title": "Einstellungen",
"admin.config.category.general": "Allgemein",
"admin.config.category.share": "Freigabe",

View File

@@ -414,6 +414,9 @@ export default {
// END /privacy
// /admin/config
"admin.config.config-file-warning.title": "Configuration file present",
"admin.config.config-file-warning.description": "As you have a configured Pingvin Share with a configuration file, you can't change the configuration through the UI.",
"admin.config.title": "Configuration",
"admin.config.category.general": "General",
"admin.config.category.share": "Share",

View File

@@ -1,4 +1,5 @@
import {
Alert,
AppShell,
Box,
Button,
@@ -13,6 +14,7 @@ import { useMediaQuery } from "@mantine/hooks";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { TbInfoCircle } from "react-icons/tb";
import { FormattedMessage } from "react-intl";
import Meta from "../../../components/Meta";
import AdminConfigInput from "../../../components/admin/configuration/AdminConfigInput";
@@ -46,6 +48,10 @@ export default function AppShellDemo() {
const [logo, setLogo] = useState<File | null>(null);
const isEditingAllowed = (): boolean => {
return !configVariables || configVariables[0].allowEdit;
};
const saveConfigVariables = async () => {
if (logo) {
configService
@@ -132,6 +138,17 @@ export default function AppShellDemo() {
) : (
<>
<Stack>
{!isEditingAllowed() && (
<Alert
mb={"lg"}
variant="light"
color="primary"
title={t("admin.config.config-file-warning.title")}
icon={<TbInfoCircle />}
>
<FormattedMessage id="admin.config.config-file-warning.description" />
</Alert>
)}
<Title mb="md" order={3}>
{t("admin.config.category." + categoryId)}
</Title>

View File

@@ -16,6 +16,7 @@ export type AdminConfig = Config & {
secret: boolean;
description: string;
obscured: boolean;
allowEdit: boolean;
};
export type AdminConfigGroupedByCategory = {