diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index b5f7fa8d253..1fabe634f94 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -3473,3 +3473,5 @@ authTokenClientSecret=Auth Token Client Secret enableDebugSMTP=Enable Debug SMTP signatureMaxExp=Max expiration signatureMaxExpHelp=Maximum expiration allowed for the JWT. Tokens need to be generated right before authentication. After this period will be considered invalid because they are too old. If undefined the default value is 60 seconds. +fileNameDialogTitle=Save as +fileName=File name \ No newline at end of file diff --git a/js/apps/admin-ui/src/realm-settings/themes/FileNameDialog.tsx b/js/apps/admin-ui/src/realm-settings/themes/FileNameDialog.tsx new file mode 100644 index 00000000000..d42988c9fbd --- /dev/null +++ b/js/apps/admin-ui/src/realm-settings/themes/FileNameDialog.tsx @@ -0,0 +1,39 @@ +import { TextControl } from "@keycloak/keycloak-ui-shared"; +import { Form } from "@patternfly/react-core"; +import { ConfirmDialogModal } from "../../components/confirm-dialog/ConfirmDialog"; +import { useTranslation } from "react-i18next"; +import { FormProvider, useForm } from "react-hook-form"; + +type FileNameDialogProps = { + onSave: (fileName: string) => void; + onClose: () => void; +}; + +type FormValues = { + fileName: string; +}; +export const FileNameDialog = ({ onSave, onClose }: FileNameDialogProps) => { + const { t } = useTranslation(); + const form = useForm(); + const { handleSubmit } = form; + + const save = ({ fileName }: FormValues) => onSave(fileName); + return ( + handleSubmit(save)()} + > +
+ + + +
+
+ ); +}; diff --git a/js/apps/admin-ui/src/realm-settings/themes/ThemeColors.tsx b/js/apps/admin-ui/src/realm-settings/themes/ThemeColors.tsx index 3dca6970e98..3a37c4d1d19 100644 --- a/js/apps/admin-ui/src/realm-settings/themes/ThemeColors.tsx +++ b/js/apps/admin-ui/src/realm-settings/themes/ThemeColors.tsx @@ -23,6 +23,8 @@ import { import { useTranslation } from "react-i18next"; import { FixedButtonsGroup } from "../../components/form/FixedButtonGroup"; import { FormAccess } from "../../components/form/FormAccess"; +import useToggle from "../../utils/useToggle"; +import { FileNameDialog } from "./FileNameDialog"; import { ImageUpload } from "./ImageUpload"; import { usePreviewLogo } from "./LogoContext"; import { darkTheme, lightTheme } from "./PatternflyVars"; @@ -81,6 +83,7 @@ export const ThemeColors = ({ realm, save, theme }: ThemeColorsProps) => { const { handleSubmit, watch } = form; const style = watch(); const contextLogo = usePreviewLogo(); + const [open, toggle, setOpen] = useToggle(); const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const mapping = useMemo( @@ -116,6 +119,7 @@ export const ThemeColors = ({ realm, save, theme }: ThemeColorsProps) => { favicon: values.favicon as File, logo: values.logo as File, bgimage: values.bgimage as File, + fileName: values.name as string, attributes: { ...realm.attributes, style: JSON.stringify({ @@ -135,54 +139,65 @@ export const ThemeColors = ({ realm, save, theme }: ThemeColorsProps) => { }, [realm]); return ( - - - {t("themeColorInfo")} - - {mediaQuery.matches && theme === "light" && ( - + <> + {open && ( + { + handleSubmit((data) => convert({ ...data, name }))(); + setOpen(false); + }} + onClose={toggle} + /> )} - - - - - - - - - contextLogo?.setLogo(logo)} - /> - - - - - {mapping.map((m) => ( - - ))} - - - - - - - - - - - + + + {t("themeColorInfo")} + + {mediaQuery.matches && theme === "light" && ( + + )} + + + + + + + + + contextLogo?.setLogo(logo)} + /> + + + + + {mapping.map((m) => ( + + ))} + + + + + + + + + + + + ); }; diff --git a/js/apps/admin-ui/src/realm-settings/themes/ThemesTab.tsx b/js/apps/admin-ui/src/realm-settings/themes/ThemesTab.tsx index 51bf99cb452..4dbcb2a49e6 100644 --- a/js/apps/admin-ui/src/realm-settings/themes/ThemesTab.tsx +++ b/js/apps/admin-ui/src/realm-settings/themes/ThemesTab.tsx @@ -21,6 +21,7 @@ type ThemesTabProps = { }; export type ThemeRealmRepresentation = RealmRepresentation & { + fileName?: string; favicon?: File; logo?: File; bgimage?: File; @@ -37,7 +38,7 @@ export default function ThemesTab({ realm, save }: ThemesTabProps) { const styles = JSON.parse(realm.attributes?.style ?? "{}"); - const { favicon, logo, bgimage, ...rest } = realm; + const { favicon, logo, bgimage, fileName, ...rest } = realm; const logoName = "img/logo" + logo?.name?.substring(logo?.name?.lastIndexOf(".")); @@ -135,7 +136,7 @@ styles=css/login.css css/theme-styles.css const url = URL.createObjectURL(content); const a = document.createElement("a"); a.href = url; - a.download = "quick-theme.jar"; + a.download = fileName || "quick-theme.jar"; a.click(); URL.revokeObjectURL(url); });