From 331ce510851aed6efcc2f32199fa810b3019a667 Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Mon, 11 Sep 2023 02:57:32 +0200 Subject: [PATCH 01/29] =?UTF-8?q?=E2=9C=A8=20Removes=20trailing=20slashes?= =?UTF-8?q?=20from=20URLs=20on=20save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/Modals/EditAppModal/EditAppModal.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx index c447115d6..b8d19ae29 100644 --- a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx @@ -11,11 +11,12 @@ import { IconPlug, } from '@tabler/icons-react'; import { useTranslation } from 'next-i18next'; +import { removeTrailingSlash } from 'next/dist/shared/lib/router/utils/remove-trailing-slash'; import { useState } from 'react'; - import { useConfigContext } from '~/config/provider'; import { useConfigStore } from '~/config/store'; import { AppType } from '~/types/app'; + import { DebouncedImage } from '../../../IconSelector/DebouncedImage'; import { useEditModeStore } from '../../Views/useEditModeStore'; import { AppearanceTab } from './Tabs/AppereanceTab/AppereanceTab'; @@ -90,6 +91,9 @@ export const EditAppModal = ({ return; } + values.url = removeTrailingSlash(values.url); + values.behaviour.externalUrl = removeTrailingSlash(values.behaviour.externalUrl); + updateConfig( configName, (previousConfig) => ({ From 3c015d297b13d256149b351862cca98882562e75 Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Mon, 11 Sep 2023 02:58:05 +0200 Subject: [PATCH 02/29] =?UTF-8?q?=E2=9C=A8=20Add=20common=20troubleshootin?= =?UTF-8?q?g=20prompt=20on=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/layout/modals/add-app.json | 13 +++++- .../Tabs/GeneralTab/GeneralTab.tsx | 46 +++++++++++++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/public/locales/en/layout/modals/add-app.json b/public/locales/en/layout/modals/add-app.json index afa4b7540..b9ecdd46b 100644 --- a/public/locales/en/layout/modals/add-app.json +++ b/public/locales/en/layout/modals/add-app.json @@ -13,7 +13,18 @@ }, "internalAddress": { "label": "Internal address", - "description": "Internal IP-address of the app." + "description": "Internal IP-address of the app.", + "troubleshoot": { + "label": "Common Troubleshooting", + "header": "This is a list of commonly made mistake and troubleshooting:", + "lines": { + "nothingAfterPort": "You should, in most if not all cases, not input anything after the port, even the '/admin' for pihole.", + "protocolCheck": "Always make sure that the URL is preceded by http or https, and to make sure you are using the right one.", + "iframe": "When it comes to iframes, those should always be using the same protocol (http/s) as Homarr.", + "clearCache": "Some informations are registered in cache, so an integration might not work unless you clear the cache in Homarr's general options." + }, + "footer": "For more troubleshooting, reach out on our {{discord}}." + } }, "externalAddress": { "label": "External address", diff --git a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx index 16d8f6194..979cfc1ae 100644 --- a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx @@ -1,9 +1,10 @@ -import { Stack, Tabs, Text, TextInput } from '@mantine/core'; +import { Anchor, Button, Card, Collapse, Group, Stack, Tabs, Text, TextInput } from '@mantine/core'; import { UseFormReturnType } from '@mantine/form'; -import { IconClick, IconCursorText, IconLink } from '@tabler/icons-react'; +import { useDisclosure } from '@mantine/hooks'; +import { IconAlertCircle, IconClick, IconCursorText, IconLink } from '@tabler/icons-react'; import { useTranslation } from 'next-i18next'; - import { AppType } from '~/types/app'; + import { EditAppModalTab } from '../type'; interface GeneralTabProps { @@ -13,6 +14,16 @@ interface GeneralTabProps { export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { const { t } = useTranslation('layout/modals/add-app'); + + const [opened, { toggle }] = useDisclosure(false); + + const commonMistakes = [ + t('general.internalAddress.troubleshoot.lines.nothingAfterPort'), + t('general.internalAddress.troubleshoot.lines.protocolCheck'), + t('general.internalAddress.troubleshoot.lines.iframe'), + t('general.internalAddress.troubleshoot.lines.clearCache'), + ]; + return ( @@ -46,12 +57,39 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { {...form.getInputProps('behaviour.externalUrl')} /> + + + + + + + {t('general.internalAddress.troubleshoot.header')} + {commonMistakes.map((value: string, key: number) => { + return ( + + + {value} + + ); + })} + + {t('general.internalAddress.troubleshoot.footer').split('{{discord}}')[0]} + + Discord + + {t('general.internalAddress.troubleshoot.footer').split('{{discord}}')[1]} + + + + {!form.values.behaviour.externalUrl.startsWith('https://') && !form.values.behaviour.externalUrl.startsWith('http://') && ( {t('behaviour.customProtocolWarning')} - )} + )} ); From 24024cc7f2539e292e1290048b763604ed29cbec Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Thu, 12 Oct 2023 19:23:16 +0200 Subject: [PATCH 03/29] =?UTF-8?q?=F0=9F=8E=A8=20Added=20troubleshoot=20ste?= =?UTF-8?q?ps=20+=20external=20address=20"/"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/layout/modals/add-app.json | 2 ++ src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx | 1 - .../Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/public/locales/en/layout/modals/add-app.json b/public/locales/en/layout/modals/add-app.json index b9ecdd46b..f975210f8 100644 --- a/public/locales/en/layout/modals/add-app.json +++ b/public/locales/en/layout/modals/add-app.json @@ -20,6 +20,8 @@ "lines": { "nothingAfterPort": "You should, in most if not all cases, not input anything after the port, even the '/admin' for pihole.", "protocolCheck": "Always make sure that the URL is preceded by http or https, and to make sure you are using the right one.", + "preferIP": "It is recommended to use the direct ip of the machine or container you are trying to communicate with.", + "wget": "To make sure that homarr can communicate with the other apps, make sure to wget/curl/ping the app's IP:port.", "iframe": "When it comes to iframes, those should always be using the same protocol (http/s) as Homarr.", "clearCache": "Some informations are registered in cache, so an integration might not work unless you clear the cache in Homarr's general options." }, diff --git a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx index b8d19ae29..7ff6e3058 100644 --- a/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/EditAppModal.tsx @@ -92,7 +92,6 @@ export const EditAppModal = ({ } values.url = removeTrailingSlash(values.url); - values.behaviour.externalUrl = removeTrailingSlash(values.behaviour.externalUrl); updateConfig( configName, diff --git a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx index 979cfc1ae..aa6f56f85 100644 --- a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx @@ -20,6 +20,8 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { const commonMistakes = [ t('general.internalAddress.troubleshoot.lines.nothingAfterPort'), t('general.internalAddress.troubleshoot.lines.protocolCheck'), + t('general.internalAddress.troubleshoot.lines.preferIP'), + t('general.internalAddress.troubleshoot.lines.wget'), t('general.internalAddress.troubleshoot.lines.iframe'), t('general.internalAddress.troubleshoot.lines.clearCache'), ]; From 5b3a236194884243038cb0479c4f1dff770c5133 Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Fri, 27 Oct 2023 23:10:42 +0200 Subject: [PATCH 04/29] =?UTF-8?q?=E2=9C=A8=20Add=20401=20page=20(#1508)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../en/layout/errors/access-denied.json | 5 ++ src/images/undraw_secure_login_pdn4.svg | 1 + src/pages/401.tsx | 55 +++++++++++++++++++ src/pages/board/[slug]/customize.tsx | 23 ++++---- src/pages/board/index.tsx | 13 ++--- src/pages/manage/index.tsx | 8 +-- src/pages/manage/tools/docker.tsx | 20 +++---- src/pages/manage/users/index.tsx | 9 ++- src/pages/manage/users/invites.tsx | 9 ++- src/tools/server/loginBuilder.ts | 8 ++- src/tools/server/translation-namespaces.ts | 2 + 11 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 public/locales/en/layout/errors/access-denied.json create mode 100644 src/images/undraw_secure_login_pdn4.svg create mode 100644 src/pages/401.tsx diff --git a/public/locales/en/layout/errors/access-denied.json b/public/locales/en/layout/errors/access-denied.json new file mode 100644 index 000000000..d1132e481 --- /dev/null +++ b/public/locales/en/layout/errors/access-denied.json @@ -0,0 +1,5 @@ +{ + "title": "Access denied", + "text": "You do not have sufficient permissions to access this page. If you believe, that this is not intentional, please contact your administrator.", + "switchAccount": "Switch to a different account" +} \ No newline at end of file diff --git a/src/images/undraw_secure_login_pdn4.svg b/src/images/undraw_secure_login_pdn4.svg new file mode 100644 index 000000000..97c35f957 --- /dev/null +++ b/src/images/undraw_secure_login_pdn4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/401.tsx b/src/pages/401.tsx new file mode 100644 index 000000000..e9bf268bb --- /dev/null +++ b/src/pages/401.tsx @@ -0,0 +1,55 @@ +import { Button, Center, Stack, Title, Text, createStyles } from "@mantine/core"; +import { useTranslation } from "next-i18next"; +import Image from "next/image"; +import Head from "next/head"; +import { MainLayout } from "~/components/layout/Templates/MainLayout"; +import Link from "next/link"; + +import imageAccessDenied from '~/images/undraw_secure_login_pdn4.svg'; +import { pageAccessDeniedNamespaces } from "~/tools/server/translation-namespaces"; +import { getServerSideTranslations } from "~/tools/server/getServerSideTranslations"; +import { GetServerSidePropsContext } from "next"; + +export default function Custom401() { + const { classes } = useStyles(); + const { t } = useTranslation('layout/errors/access-denied'); + return ( + +
+ + Access denied • Homarr + + + + {t('title')} + {t('text')} + + + +
+
+ ) +} + +export async function getStaticProps({ req, res, locale }: GetServerSidePropsContext) { + const translations = await getServerSideTranslations( + [...pageAccessDeniedNamespaces, 'common'], + locale, + req, + res + ); + return { + props: { + ...translations, + }, + }; +} + +const useStyles = createStyles(() => ({ + image: { + margin: '0 auto', + display: 'block', + }, +})); \ No newline at end of file diff --git a/src/pages/board/[slug]/customize.tsx b/src/pages/board/[slug]/customize.tsx index bb78e96ff..45d465b54 100644 --- a/src/pages/board/[slug]/customize.tsx +++ b/src/pages/board/[slug]/customize.tsx @@ -44,6 +44,7 @@ import { MainLayout } from '~/components/layout/Templates/MainLayout'; import { createTrpcServersideHelpers } from '~/server/api/helper'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { firstUpperCase } from '~/tools/shared/strings'; import { api } from '~/utils/api'; import { useI18nZodResolver } from '~/utils/i18n-zod-resolver'; @@ -275,22 +276,22 @@ const routeParamsSchema = z.object({ slug: z.string(), }); -export const getServerSideProps: GetServerSideProps = async ({ req, res, locale, params }) => { - const routeParams = routeParamsSchema.safeParse(params); +export const getServerSideProps: GetServerSideProps = async (context) => { + const routeParams = routeParamsSchema.safeParse(context.params); if (!routeParams.success) { return { notFound: true, }; } - const session = await getServerAuthSession({ req, res }); - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const session = await getServerAuthSession({ req: context.req, res: context.res }); + + const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true); + if (result) { + return result; } - const helpers = await createTrpcServersideHelpers({ req, res }); + const helpers = await createTrpcServersideHelpers({ req: context.req, res: context.res }); const config = await helpers.config.byName.fetch({ name: routeParams.data.slug }); @@ -305,9 +306,9 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, locale, 'settings/customization/gridstack', 'settings/customization/access', ], - locale, - req, - res + context.locale, + context.req, + context.res ); return { diff --git a/src/pages/board/index.tsx b/src/pages/board/index.tsx index 6a283e919..95f100d33 100644 --- a/src/pages/board/index.tsx +++ b/src/pages/board/index.tsx @@ -11,6 +11,7 @@ import { getDefaultBoardAsync } from '~/server/db/queries/userSettings'; import { userSettings } from '~/server/db/schema'; import { getFrontendConfig } from '~/tools/config/getFrontendConfig'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { ConfigType } from '~/types/config'; @@ -45,15 +46,9 @@ export const getServerSideProps: GetServerSideProps = a ); const config = await getFrontendConfig(boardName); - if (!config?.settings?.access?.allowGuests && !session?.user) { - return { - notFound: true, - props: { - primaryColor: config.settings.customization.colors.primary, - secondaryColor: config.settings.customization.colors.secondary, - primaryShade: config.settings.customization.colors.shade, - }, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => true); + if (result) { + return result; } return { diff --git a/src/pages/manage/index.tsx b/src/pages/manage/index.tsx index 0386a274b..281a7ef8d 100644 --- a/src/pages/manage/index.tsx +++ b/src/pages/manage/index.tsx @@ -23,6 +23,7 @@ import { getServerSideTranslations } from '~/tools/server/getServerSideTranslati import { OnlyKeysWithStructure } from '~/types/helpers'; import { type quickActions } from '../../../public/locales/en/manage/index.json'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; const ManagementPage = () => { const { t } = useTranslation('manage/index'); @@ -118,10 +119,9 @@ const QuickActionCard = ({ type, href }: QuickActionCardProps) => { export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - if (!session?.user) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/pages/manage/tools/docker.tsx b/src/pages/manage/tools/docker.tsx index 90793a973..f0cc714d4 100644 --- a/src/pages/manage/tools/docker.tsx +++ b/src/pages/manage/tools/docker.tsx @@ -11,6 +11,7 @@ import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { dockerRouter } from '~/server/api/routers/docker/router'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -54,24 +55,23 @@ export default function DockerPage({ ); } -export const getServerSideProps: GetServerSideProps = async ({ locale, req, res }) => { - const session = await getServerAuthSession({ req, res }); - if (!session?.user.isAdmin) { - return { - notFound: true, - }; +export const getServerSideProps: GetServerSideProps = async (context) => { + const session = await getServerAuthSession({ req: context.req, res: context.res }); + const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const caller = dockerRouter.createCaller({ session: session, - cookies: req.cookies, + cookies: context.req.cookies, }); const translations = await getServerSideTranslations( [...boardNamespaces, 'layout/manage', 'tools/docker'], - locale, - req, - res + context.locale, + context.req, + context.res ); let containers = []; diff --git a/src/pages/manage/users/index.tsx b/src/pages/manage/users/index.tsx index fcf32d686..4a3b3176b 100644 --- a/src/pages/manage/users/index.tsx +++ b/src/pages/manage/users/index.tsx @@ -26,6 +26,7 @@ import { openDeleteUserModal } from '~/components/Manage/User/delete-user.modal' import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -180,11 +181,9 @@ const ManageUsersPage = () => { export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/pages/manage/users/invites.tsx b/src/pages/manage/users/invites.tsx index 5d491337f..526524633 100644 --- a/src/pages/manage/users/invites.tsx +++ b/src/pages/manage/users/invites.tsx @@ -20,6 +20,7 @@ import { openCreateInviteModal } from '~/components/Manage/User/Invite/create-in import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -152,11 +153,9 @@ const useStyles = createStyles(() => ({ export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/tools/server/loginBuilder.ts b/src/tools/server/loginBuilder.ts index 3f84f2b7e..297076c47 100644 --- a/src/tools/server/loginBuilder.ts +++ b/src/tools/server/loginBuilder.ts @@ -4,7 +4,9 @@ import { GetServerSidePropsResult, PreviewData, } from 'next'; + import { Session } from 'next-auth'; + import { ParsedUrlQuery } from 'querystring'; export const checkForSessionOrAskForLogin = ( @@ -13,7 +15,6 @@ export const checkForSessionOrAskForLogin = ( accessCallback: () => boolean ): GetServerSidePropsResult | undefined => { if (!session?.user) { - console.log('detected logged out user!'); return { props: {}, redirect: { @@ -26,7 +27,10 @@ export const checkForSessionOrAskForLogin = ( if (!accessCallback()) { return { props: {}, - notFound: true, + redirect: { + destination: '/401', + permanent: false + } }; } diff --git a/src/tools/server/translation-namespaces.ts b/src/tools/server/translation-namespaces.ts index 695edcb2d..138a0a962 100644 --- a/src/tools/server/translation-namespaces.ts +++ b/src/tools/server/translation-namespaces.ts @@ -51,3 +51,5 @@ export const manageNamespaces = [ export const loginNamespaces = ['authentication/login']; export const pageNotFoundNamespaces = ['layout/errors/not-found']; + +export const pageAccessDeniedNamespaces = ['layout/errors/access-denied']; From ac3c0884924978b60773dbba81700b36d68395ed Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Sat, 28 Oct 2023 20:01:14 +0200 Subject: [PATCH 05/29] =?UTF-8?q?=F0=9F=90=9B=20adguard=20removed=20max=20?= =?UTF-8?q?test=20on=20process=20time=20(#1512)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/server/sdk/adGuard/adGuard.schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/server/sdk/adGuard/adGuard.schema.ts b/src/tools/server/sdk/adGuard/adGuard.schema.ts index 556db1ffb..ce4d6d8a8 100644 --- a/src/tools/server/sdk/adGuard/adGuard.schema.ts +++ b/src/tools/server/sdk/adGuard/adGuard.schema.ts @@ -14,7 +14,7 @@ export const adGuardApiStatsResponseSchema = z.object({ num_replaced_safebrowsing: z.number().min(0), num_replaced_safesearch: z.number().min(0), num_replaced_parental: z.number().min(0), - avg_processing_time: z.number().min(0).max(1), + avg_processing_time: z.number().min(0), }); export const adGuardApiStatusResponseSchema = z.object({ From d97850aaad7ffc2ca9bf6c8c783900af4696da2b Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Mon, 30 Oct 2023 03:07:38 +0100 Subject: [PATCH 06/29] =?UTF-8?q?=F0=9F=90=9BClock=20fix=20timezone=20name?= =?UTF-8?q?d=20offset=20format=20for=20dayjs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/date/DateTile.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widgets/date/DateTile.tsx b/src/widgets/date/DateTile.tsx index 1fbbdbbef..91df9bcb3 100644 --- a/src/widgets/date/DateTile.tsx +++ b/src/widgets/date/DateTile.tsx @@ -2,6 +2,7 @@ import { Stack, Text, createStyles } from '@mantine/core'; import { useElementSize } from '@mantine/hooks'; import { IconClock } from '@tabler/icons-react'; import dayjs from 'dayjs'; +import advancedFormat from 'dayjs/plugin/advancedFormat'; import timezones from 'dayjs/plugin/timezone'; import utc from 'dayjs/plugin/utc'; import { useSession } from 'next-auth/react'; @@ -13,6 +14,7 @@ import { api } from '~/utils/api'; import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; +dayjs.extend(advancedFormat); dayjs.extend(utc); dayjs.extend(timezones); From 4aa09b7e9598e912362303b44172e87fd3e1e0e1 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 13:57:09 +0100 Subject: [PATCH 07/29] =?UTF-8?q?=F0=9F=90=9B=20Fix=20unknown=20country=20?= =?UTF-8?q?in=20tRPC=20`citySchema`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/api/routers/weather.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/api/routers/weather.ts b/src/server/api/routers/weather.ts index 124f42d45..ac83728b3 100644 --- a/src/server/api/routers/weather.ts +++ b/src/server/api/routers/weather.ts @@ -5,8 +5,8 @@ import { adminProcedure, createTRPCRouter, publicProcedure } from '../trpc'; const citySchema = z.object({ id: z.number(), name: z.string(), - country: z.string(), - country_code: z.string(), + country: z.string().optional(), + country_code: z.string().optional(), latitude: z.number(), longitude: z.number(), population: z.number().optional(), From 9d334e23c8bb6a288486c4084f232e2f5d72ec44 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 13:57:40 +0100 Subject: [PATCH 08/29] =?UTF-8?q?=F0=9F=90=9B=20Fix=20RSS=20widget=20descr?= =?UTF-8?q?iption?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/modules/rss.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales/en/modules/rss.json b/public/locales/en/modules/rss.json index ee73f375b..20b827fcd 100644 --- a/public/locales/en/modules/rss.json +++ b/public/locales/en/modules/rss.json @@ -1,7 +1,7 @@ { "descriptor": { "name": "RSS Widget", - "description": "", + "description": "The rss widget allows you to display RSS feeds on your dashboard.", "settings": { "title": "Settings for RSS widget", "rssFeedUrl": { From 2c4560d13a6a34897a3189608431a6e902784921 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 13:58:37 +0100 Subject: [PATCH 09/29] Add Chinese traditional as `zh-tw` --- next-i18next.config.js | 1 + src/tools/language.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/next-i18next.config.js b/next-i18next.config.js index 779df3a63..ffc557629 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -24,6 +24,7 @@ module.exports = { 'vi', 'uk', 'zh', + 'zh-tw', 'el', 'sk', 'no', diff --git a/src/tools/language.ts b/src/tools/language.ts index 69cabde0e..aba56bac2 100644 --- a/src/tools/language.ts +++ b/src/tools/language.ts @@ -179,14 +179,24 @@ export const languages = [ country: 'VN', locale: 'vi', }, + // Chinese (Simplified) { shortName: 'zh', originalName: '中文', - translatedName: 'Chinese', + translatedName: 'Chinese (Simplified)', emoji: '🇨🇳', country: 'CN', locale: 'zh-cn', }, + // Chinese (Traditional) + { + shortName: 'zh-tw', + originalName: '中文(台灣)', + translatedName: 'Chinese (Traditional)', + emoji: '🇹🇼', + country: 'TW', + locale: 'zh-tw', + }, { originalName: 'Ελληνικά', translatedName: 'Greek', From 2e481e2103621ef5cbad2859fe4706cbe26b6746 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 15:04:21 +0100 Subject: [PATCH 10/29] =?UTF-8?q?=F0=9F=90=9B=20await=20for=20GeoTz=20in?= =?UTF-8?q?=20timezone=20finder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/api/routers/timezone.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/api/routers/timezone.ts b/src/server/api/routers/timezone.ts index eca5f45bc..86a0979be 100644 --- a/src/server/api/routers/timezone.ts +++ b/src/server/api/routers/timezone.ts @@ -13,7 +13,7 @@ export const timezoneRouter = createTRPCRouter({ }) ) .query(async ({ input }) => { - const timezone = GeoTz.find(input.latitude, input.longitude); + const timezone = await GeoTz.find(input.latitude, input.longitude); return Array.isArray(timezone) ? timezone[0] : timezone; }), }); From 7ba9065fb7684ff19f3b264fc425eb73fd33d28f Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 15:15:33 +0100 Subject: [PATCH 11/29] =?UTF-8?q?=E2=9C=A8=20Fetch=20the=20weather=20using?= =?UTF-8?q?=20a=20local=20request=20instead=20of=20a=20server-side=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for request caching on the disk using node's fetch --- src/server/api/routers/weather.ts | 14 -------------- src/widgets/weather/WeatherTile.tsx | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/server/api/routers/weather.ts b/src/server/api/routers/weather.ts index ac83728b3..e2a64fb22 100644 --- a/src/server/api/routers/weather.ts +++ b/src/server/api/routers/weather.ts @@ -36,20 +36,6 @@ export const weatherRouter = createTRPCRouter({ }) ) .query(async ({ input }) => fetchCity(input.query)), - at: publicProcedure - .input( - z.object({ - longitude: z.number(), - latitude: z.number(), - }) - ) - .output(weatherSchema) - .query(async ({ input }) => { - const res = await fetch( - `https://api.open-meteo.com/v1/forecast?latitude=${input.latitude}&longitude=${input.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min¤t_weather=true&timezone=Europe%2FLondon` - ); - return res.json(); - }), }); export type City = z.infer; diff --git a/src/widgets/weather/WeatherTile.tsx b/src/widgets/weather/WeatherTile.tsx index 1ace62447..7a51d5479 100644 --- a/src/widgets/weather/WeatherTile.tsx +++ b/src/widgets/weather/WeatherTile.tsx @@ -6,8 +6,8 @@ import { IconCloudRain, IconMapPin, } from '@tabler/icons-react'; +import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; -import { api } from '~/utils/api'; import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; @@ -50,7 +50,23 @@ interface WeatherTileProps { } function WeatherTile({ widget }: WeatherTileProps) { - const { data: weather, isLoading, isError } = api.weather.at.useQuery(widget.properties.location); + const { + data: weather, + isLoading, + isError, + } = useQuery( + ['weather', widget.properties.location], + async () => + await fetch( + `https://api.open-meteo.com/v1/forecast?latitude=${widget.properties.location.latitude}&longitude=${widget.properties.location.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min¤t_weather=true&timezone=Europe%2FLondon`, + { + // 15 minutes of cache + cache: 'force-cache', + headers: { 'Cache-Control': 'max-age=900' }, + } + ).then((res) => res.json()), + {} + ); const { width, ref } = useElementSize(); const { t } = useTranslation('modules/weather'); From 92ffce1b3b96d3b4d0631c7c8ecc5b5d5e1ffd18 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 16:19:17 +0100 Subject: [PATCH 12/29] =?UTF-8?q?=F0=9F=90=9B=20Fix=20walks=20repository?= =?UTF-8?q?=20not=20up=20to=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/api/routers/icon.ts | 5 +- .../server/images/github-icons-repository.ts | 75 +++++++++++++++++++ .../images/jsdelivr-icons-repository.ts | 7 +- 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 src/tools/server/images/github-icons-repository.ts diff --git a/src/server/api/routers/icon.ts b/src/server/api/routers/icon.ts index f53800d17..a5b6c2493 100644 --- a/src/server/api/routers/icon.ts +++ b/src/server/api/routers/icon.ts @@ -1,6 +1,7 @@ import { JsdelivrIconsRepository } from '~/tools/server/images/jsdelivr-icons-repository'; import { LocalIconsRepository } from '~/tools/server/images/local-icons-repository'; import { UnpkgIconsRepository } from '~/tools/server/images/unpkg-icons-repository'; +import { GitHubIconsRepository } from '~/tools/server/images/github-icons-repository'; import { createTRPCRouter, publicProcedure } from '../trpc'; @@ -8,8 +9,8 @@ export const iconRouter = createTRPCRouter({ all: publicProcedure.query(async () => { const respositories = [ new LocalIconsRepository(), - new JsdelivrIconsRepository( - JsdelivrIconsRepository.tablerRepository, + new GitHubIconsRepository( + GitHubIconsRepository.walkxcode, 'Walkxcode Dashboard Icons', 'Walkxcode on Github' ), diff --git a/src/tools/server/images/github-icons-repository.ts b/src/tools/server/images/github-icons-repository.ts new file mode 100644 index 000000000..2abb07d06 --- /dev/null +++ b/src/tools/server/images/github-icons-repository.ts @@ -0,0 +1,75 @@ +import { + AbstractIconRepository, + NormalizedIcon, + NormalizedIconRepositoryResult, +} from './abstract-icons-repository'; + +export class GitHubIconsRepository extends AbstractIconRepository { + static readonly walkxcode = { + api: 'https://api.github.com/repos/walkxcode/dashboard-icons/git/trees/main?recursive=true', + blob: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/{0}/{1}', + } as GitHubRepositoryUrl; + + constructor( + private readonly repository: GitHubRepositoryUrl, + private readonly displayName: string, + copyright: string + ) { + super(copyright); + } + + protected async fetchInternally(): Promise { + const response = await fetch(this.repository.api); + const body = (await response.json()) as GitHubRepo; + + const normalizedEntries = body.tree + .filter((file) => !['_banner.png', '_logo.png'].some((x) => file.path.includes(x))) + .filter((file) => ['.png', '.svg'].some((x) => file.path.endsWith(x))) + .map((file): NormalizedIcon => { + const fileNameParts = file.path.split('/'); + const fileName = fileNameParts[fileNameParts.length - 1]; + const extensions = fileName.split('.')[1]; + return { + url: this.repository.blob.replace('{0}', extensions).replace('{1}', fileName), + name: fileName, + size: file.size ?? 0, + }; + }); + + return { + entries: normalizedEntries, + count: normalizedEntries.length, + success: true, + name: this.displayName, + copyright: this.copyright, + }; + } +} + +type GitHubRepositoryUrl = { + api: string; + blob: string; +}; + +// Generated by https://quicktype.io + +export interface GitHubRepo { + sha: string; + url: string; + tree: Tree[]; + truncated: boolean; +} + +export interface Tree { + path: string; + mode: string; + type: Type; + sha: string; + url: string; + size?: number; +} + +export enum Type { + Blob = 'blob', + Tree = 'tree', +} diff --git a/src/tools/server/images/jsdelivr-icons-repository.ts b/src/tools/server/images/jsdelivr-icons-repository.ts index acce25790..737b1faa1 100644 --- a/src/tools/server/images/jsdelivr-icons-repository.ts +++ b/src/tools/server/images/jsdelivr-icons-repository.ts @@ -5,11 +5,6 @@ import { } from './abstract-icons-repository'; export class JsdelivrIconsRepository extends AbstractIconRepository { - static readonly tablerRepository = { - api: 'https://data.jsdelivr.com/v1/packages/gh/walkxcode/dashboard-icons@main?structure=flat', - blob: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/{0}/{1}', - } as JsdelivrRepositoryUrl; - static readonly papirusRepository = { api: 'https://data.jsdelivr.com/v1/packages/gh/PapirusDevelopmentTeam/papirus_icons@master?structure=flat', blob: 'https://cdn.jsdelivr.net/gh/PapirusDevelopmentTeam/papirus_icons/src/{1}', @@ -33,7 +28,7 @@ export class JsdelivrIconsRepository extends AbstractIconRepository { const body = (await response.json()) as JsdelivrResponse; const normalizedEntries = body.files - .filter((file) => !['_banner.png', '_logo.png'].some((x) => file.name.includes(x))) + .filter((file) => !['banner.png', 'logo.png'].some((x) => file.name.includes(x))) .filter((file) => ['.png', '.svg'].some((x) => file.name.endsWith(x))) .map((file): NormalizedIcon => { const fileNameParts = file.name.split('/'); From 6273af503b1b4df22876b846d1bb9ef2e597ce90 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 16:24:48 +0100 Subject: [PATCH 13/29] =?UTF-8?q?=F0=9F=90=9B=20Fix=20walks=20repository?= =?UTF-8?q?=20not=20up=20to=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/images/github-icons-repository.ts | 15 +++++++++++++-- .../server/images/jsdelivr-icons-repository.ts | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/server/images/github-icons-repository.ts b/src/tools/server/images/github-icons-repository.ts index 2abb07d06..38e8f19e1 100644 --- a/src/tools/server/images/github-icons-repository.ts +++ b/src/tools/server/images/github-icons-repository.ts @@ -19,12 +19,23 @@ export class GitHubIconsRepository extends AbstractIconRepository { } protected async fetchInternally(): Promise { - const response = await fetch(this.repository.api); + const response = await fetch(this.repository.api, { + + }); const body = (await response.json()) as GitHubRepo; const normalizedEntries = body.tree - .filter((file) => !['_banner.png', '_logo.png'].some((x) => file.path.includes(x))) + .filter((file) => !['banner.png', 'logo.png'].some((x) => file.path.includes(x))) .filter((file) => ['.png', '.svg'].some((x) => file.path.endsWith(x))) + .sort((a, b) => { + if (a.path.endsWith('.svg') && b.path.endsWith('.png')) { + return -1; + } + if (a.path.endsWith('.png') && b.path.endsWith('.svg')) { + return 1; + } + return 0; + }) .map((file): NormalizedIcon => { const fileNameParts = file.path.split('/'); const fileName = fileNameParts[fileNameParts.length - 1]; diff --git a/src/tools/server/images/jsdelivr-icons-repository.ts b/src/tools/server/images/jsdelivr-icons-repository.ts index 737b1faa1..19cf7b164 100644 --- a/src/tools/server/images/jsdelivr-icons-repository.ts +++ b/src/tools/server/images/jsdelivr-icons-repository.ts @@ -28,8 +28,9 @@ export class JsdelivrIconsRepository extends AbstractIconRepository { const body = (await response.json()) as JsdelivrResponse; const normalizedEntries = body.files - .filter((file) => !['banner.png', 'logo.png'].some((x) => file.name.includes(x))) + .filter((file) => !['_banner.png', '_logo.png'].some((x) => file.name.includes(x))) .filter((file) => ['.png', '.svg'].some((x) => file.name.endsWith(x))) + .map((file): NormalizedIcon => { const fileNameParts = file.name.split('/'); const fileName = fileNameParts[fileNameParts.length - 1]; From a957db7deffdbc435ba3a563b75e1a8967f899fc Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 18:55:45 +0100 Subject: [PATCH 14/29] =?UTF-8?q?=E2=9A=B0=EF=B8=8F=20Remove=20docker=20on?= =?UTF-8?q?=20index=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout/Templates/BoardLayout.tsx | 24 +++---------------- src/pages/board/index.tsx | 4 +--- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/src/components/layout/Templates/BoardLayout.tsx b/src/components/layout/Templates/BoardLayout.tsx index bd637463f..89a6a7ccd 100644 --- a/src/components/layout/Templates/BoardLayout.tsx +++ b/src/components/layout/Templates/BoardLayout.tsx @@ -26,18 +26,17 @@ import { MainLayout } from './MainLayout'; import { env } from 'process'; type BoardLayoutProps = { - dockerEnabled: boolean; children: React.ReactNode; }; -export const BoardLayout = ({ children, dockerEnabled }: BoardLayoutProps) => { +export const BoardLayout = ({ children }: BoardLayoutProps) => { const { config } = useConfigContext(); const { data: session } = useSession(); return ( } + headerActions={} > @@ -47,36 +46,19 @@ export const BoardLayout = ({ children, dockerEnabled }: BoardLayoutProps) => { ); }; -type HeaderActionProps = { - dockerEnabled: boolean; -}; - -export const HeaderActions = ({ dockerEnabled }: HeaderActionProps) => { +export const HeaderActions = () => { const { data: sessionData } = useSession(); if (!sessionData?.user?.isAdmin) return null; return ( <> - {dockerEnabled && } ); }; -const DockerButton = () => { - const { t } = useTranslation('modules/docker'); - - return ( - - - - - - ); -}; - const CustomizeBoardButton = () => { const { name } = useConfigContext(); const { t } = useTranslation('boards/common'); diff --git a/src/pages/board/index.tsx b/src/pages/board/index.tsx index 95f100d33..c30a1767f 100644 --- a/src/pages/board/index.tsx +++ b/src/pages/board/index.tsx @@ -17,12 +17,11 @@ import { ConfigType } from '~/types/config'; export default function BoardPage({ config: initialConfig, - dockerEnabled, }: InferGetServerSidePropsType) { useInitConfig(initialConfig); return ( - + ); @@ -57,7 +56,6 @@ export const getServerSideProps: GetServerSideProps = a primaryColor: config.settings.customization.colors.primary, secondaryColor: config.settings.customization.colors.secondary, primaryShade: config.settings.customization.colors.shade, - dockerEnabled: !!env.DOCKER_HOST && !!env.DOCKER_PORT, ...translations, }, }; From 503b5b0b350b9bf65ff9cfc5a2c56b7caf39e9ac Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Mon, 30 Oct 2023 19:57:44 +0100 Subject: [PATCH 15/29] =?UTF-8?q?=F0=9F=92=84=20Moved=20button=20?= =?UTF-8?q?=F0=9F=92=AC=20Added=20troubleshoot=20steps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/layout/modals/add-app.json | 7 ++++--- .../EditAppModal/Tabs/GeneralTab/GeneralTab.tsx | 13 ++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/public/locales/en/layout/modals/add-app.json b/public/locales/en/layout/modals/add-app.json index f975210f8..ce8d7f37c 100644 --- a/public/locales/en/layout/modals/add-app.json +++ b/public/locales/en/layout/modals/add-app.json @@ -15,12 +15,13 @@ "label": "Internal address", "description": "Internal IP-address of the app.", "troubleshoot": { - "label": "Common Troubleshooting", - "header": "This is a list of commonly made mistake and troubleshooting:", + "label": "Having issues?", + "header": "Here is a list of commonly made mistake and troubleshooting:", "lines": { - "nothingAfterPort": "You should, in most if not all cases, not input anything after the port, even the '/admin' for pihole.", + "nothingAfterPort": "You should, in most if not all cases, not input any path after the port. (Even the '/admin' for pihole or '/web' for plex)", "protocolCheck": "Always make sure that the URL is preceded by http or https, and to make sure you are using the right one.", "preferIP": "It is recommended to use the direct ip of the machine or container you are trying to communicate with.", + "enablePings": "Check that the IP is right by enabling pings. Customize Board -> Layout -> Enable pings. A little red or green bubble will appear on your app tiles and hovering it will give you it's response code (A green bubble with code 200 is expected in most cases).", "wget": "To make sure that homarr can communicate with the other apps, make sure to wget/curl/ping the app's IP:port.", "iframe": "When it comes to iframes, those should always be using the same protocol (http/s) as Homarr.", "clearCache": "Some informations are registered in cache, so an integration might not work unless you clear the cache in Homarr's general options." diff --git a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx index aa6f56f85..2d7637751 100644 --- a/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx +++ b/src/components/Dashboard/Modals/EditAppModal/Tabs/GeneralTab/GeneralTab.tsx @@ -1,7 +1,7 @@ import { Anchor, Button, Card, Collapse, Group, Stack, Tabs, Text, TextInput } from '@mantine/core'; import { UseFormReturnType } from '@mantine/form'; import { useDisclosure } from '@mantine/hooks'; -import { IconAlertCircle, IconClick, IconCursorText, IconLink } from '@tabler/icons-react'; +import { IconClick, IconCursorText, IconLink } from '@tabler/icons-react'; import { useTranslation } from 'next-i18next'; import { AppType } from '~/types/app'; @@ -21,6 +21,7 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { t('general.internalAddress.troubleshoot.lines.nothingAfterPort'), t('general.internalAddress.troubleshoot.lines.protocolCheck'), t('general.internalAddress.troubleshoot.lines.preferIP'), + t('general.internalAddress.troubleshoot.lines.enablePings'), t('general.internalAddress.troubleshoot.lines.wget'), t('general.internalAddress.troubleshoot.lines.iframe'), t('general.internalAddress.troubleshoot.lines.clearCache'), @@ -59,12 +60,6 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { {...form.getInputProps('behaviour.externalUrl')} /> - - - - {t('general.internalAddress.troubleshoot.header')} @@ -93,6 +88,10 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => { )} + + ); }; From a2e562a675575ee03f2c42ce91bc3912b964532c Mon Sep 17 00:00:00 2001 From: Thomas Camlong <49837342+ajnart@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:00:36 +0100 Subject: [PATCH 16/29] Update src/tools/server/images/github-icons-repository.ts --- src/tools/server/images/github-icons-repository.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/server/images/github-icons-repository.ts b/src/tools/server/images/github-icons-repository.ts index 38e8f19e1..a651d0932 100644 --- a/src/tools/server/images/github-icons-repository.ts +++ b/src/tools/server/images/github-icons-repository.ts @@ -62,7 +62,6 @@ type GitHubRepositoryUrl = { blob: string; }; -// Generated by https://quicktype.io export interface GitHubRepo { sha: string; From dda5b66a98e00d3c4d3c372823ddcab74fa49ebe Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 20:28:39 +0100 Subject: [PATCH 17/29] Fix crowdin links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfc2ca244..2f3949902 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@   CI Status - + @@ -28,7 +28,7 @@ Install 💻 • - + Translations 🈺 From 925fbd8ad3d685de08774a2530cfdee781c59c1e Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 30 Oct 2023 21:46:20 +0100 Subject: [PATCH 18/29] =?UTF-8?q?=F0=9F=9A=A8Fix=20compilation=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/board/[slug].tsx | 5 +---- src/pages/board/index.tsx | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pages/board/[slug].tsx b/src/pages/board/[slug].tsx index cd2056a6a..f8974e394 100644 --- a/src/pages/board/[slug].tsx +++ b/src/pages/board/[slug].tsx @@ -15,12 +15,11 @@ import { ConfigType } from '~/types/config'; export default function BoardPage({ config: initialConfig, - dockerEnabled, }: InferGetServerSidePropsType) { useInitConfig(initialConfig); return ( - + ); @@ -28,7 +27,6 @@ export default function BoardPage({ type BoardGetServerSideProps = { config: ConfigType; - dockerEnabled: boolean; _nextI18Next?: SSRConfig['_nextI18Next']; }; @@ -76,7 +74,6 @@ export const getServerSideProps: GetServerSideProps = a primaryColor: config.settings.customization.colors.primary, secondaryColor: config.settings.customization.colors.secondary, primaryShade: config.settings.customization.colors.shade, - dockerEnabled: !!env.DOCKER_HOST && !!env.DOCKER_PORT, ...translations, }, }; diff --git a/src/pages/board/index.tsx b/src/pages/board/index.tsx index c30a1767f..df32ce8e8 100644 --- a/src/pages/board/index.tsx +++ b/src/pages/board/index.tsx @@ -1,14 +1,10 @@ -import { eq } from 'drizzle-orm'; import { GetServerSideProps, InferGetServerSidePropsType } from 'next'; import { SSRConfig } from 'next-i18next'; import { Dashboard } from '~/components/Dashboard/Dashboard'; import { BoardLayout } from '~/components/layout/Templates/BoardLayout'; import { useInitConfig } from '~/config/init'; -import { env } from '~/env'; import { getServerAuthSession } from '~/server/auth'; -import { db } from '~/server/db'; import { getDefaultBoardAsync } from '~/server/db/queries/userSettings'; -import { userSettings } from '~/server/db/schema'; import { getFrontendConfig } from '~/tools/config/getFrontendConfig'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; From 53ef4a0579cf0218b7bccec64b2b6620c6f39fac Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Tue, 31 Oct 2023 00:21:01 +0100 Subject: [PATCH 19/29] =?UTF-8?q?=E2=9C=A8=20Add=20crowdin=20live-translat?= =?UTF-8?q?e=20feature!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next-i18next.config.js | 3 ++- src/pages/_app.tsx | 16 +++++++++---- src/pages/user/preferences.tsx | 5 ++-- src/tools/language.ts | 42 +++++++--------------------------- 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/next-i18next.config.js b/next-i18next.config.js index 779df3a63..6468aee9e 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -6,6 +6,7 @@ module.exports = { defaultLocale: 'en', locales: [ 'en', + 'cr', 'da', 'he', 'de', @@ -33,7 +34,7 @@ module.exports = { 'hu' ], - localeDetection: true, + localeDetection: false, }, returnEmptyString: false, appendNamespaceToCIMode: true, diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 7374e1950..5ff3dce20 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -61,7 +61,7 @@ function App( const analyticsEnabled = pageProps.analyticsEnabled ?? true; // TODO: make mapping from our locales to moment locales const language = getLanguageByCode(pageProps.session?.user?.language ?? 'en'); - require(`dayjs/locale/${language.locale}.js`); + if (language.locale !== 'cr') require(`dayjs/locale/${language.locale}.js`); dayjs.locale(language.locale); const [primaryColor, setPrimaryColor] = useState( @@ -101,12 +101,18 @@ function App( return ( <> + {pageProps.locale === 'cr' && ( + <> + + + )} {analyticsEnabled === true && ( From 780bfd6292b7b55507498733ac070cdce42dc9dd Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Tue, 31 Oct 2023 10:32:55 +0100 Subject: [PATCH 28/29] =?UTF-8?q?=F0=9F=90=9B=20Use=20session=20lanugage?= =?UTF-8?q?=20instead=20of=20locale=20for=20crowdin=20live-translate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/_app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index fb39baf95..0af2adbeb 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -101,7 +101,7 @@ function App( return ( <> - {pageProps.session.user.language === 'cr' && ( + {pageProps.session && pageProps.session.user.language === 'cr' && ( <> From e991bcd39420ac5db1cd331b83302e7cc3f31c33 Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Tue, 31 Oct 2023 19:04:59 +0100 Subject: [PATCH 29/29] =?UTF-8?q?=F0=9F=90=9B=20Access=20callback=20condit?= =?UTF-8?q?ions=20(#1536)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/board/[slug].tsx | 2 +- src/tools/server/loginBuilder.ts | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/pages/board/[slug].tsx b/src/pages/board/[slug].tsx index f8974e394..c121d93cb 100644 --- a/src/pages/board/[slug].tsx +++ b/src/pages/board/[slug].tsx @@ -62,7 +62,7 @@ export const getServerSideProps: GetServerSideProps = a const result = checkForSessionOrAskForLogin( ctx, session, - () => config.settings.access.allowGuests || !!session?.user + () => config.settings.access.allowGuests || session?.user != undefined ); if (result) { return result; diff --git a/src/tools/server/loginBuilder.ts b/src/tools/server/loginBuilder.ts index 297076c47..9f9a3a2cd 100644 --- a/src/tools/server/loginBuilder.ts +++ b/src/tools/server/loginBuilder.ts @@ -14,17 +14,10 @@ export const checkForSessionOrAskForLogin = ( session: Session | null, accessCallback: () => boolean ): GetServerSidePropsResult | undefined => { - if (!session?.user) { - return { - props: {}, - redirect: { - destination: `/auth/login?redirectAfterLogin=${context.resolvedUrl}`, - permanent: false, - }, - }; - } + const permitted = accessCallback(); - if (!accessCallback()) { + // user is logged in but does not have the required access + if (session?.user && !permitted) { return { props: {}, redirect: { @@ -34,5 +27,17 @@ export const checkForSessionOrAskForLogin = ( }; } - return undefined; + // user *may* be logged in and permitted + if (permitted) { + return undefined; + } + + // user is logged out and needs to sign in + return { + props: {}, + redirect: { + destination: `/auth/login?redirectAfterLogin=${context.resolvedUrl}`, + permanent: false, + }, + }; };