diff --git a/next.config.js b/next.config.js index 03c30c55..a1e30c36 100644 --- a/next.config.js +++ b/next.config.js @@ -11,24 +11,36 @@ const contentSecurityPolicy = [ `connect-src 'self' api.umami.is`, ]; +const cspHeader = (values = []) => ({ + key: 'Content-Security-Policy', + value: values + .join(';') + .replace(/\s{2,}/g, ' ') + .trim(), +}); + const headers = [ { key: 'X-DNS-Prefetch-Control', value: 'on', }, - !process.env.ALLOWED_FRAME_URLS && { + { key: 'X-Frame-Options', value: 'SAMEORIGIN', }, -].filter(n => n); + cspHeader(contentSecurityPolicy), +]; -const cspHeader = (values = []) => ({ - key: 'Content-Security-Policy', - value: [...contentSecurityPolicy, ...values] - .join(';') - .replace(/\s{2,}/g, ' ') - .trim(), -}); +const shareHeaders = [ + { + key: 'X-DNS-Prefetch-Control', + value: 'on', + }, + cspHeader([ + ...contentSecurityPolicy, + `frame-ancestors 'self' ${process.env.ALLOWED_FRAME_URLS || ''}`, + ]), +]; if (process.env.FORCE_SSL) { headers.push({ @@ -127,14 +139,11 @@ const config = { return [ { source: '/:path*', - headers: [ - ...headers, - cspHeader([`frame-ancestors 'self' ${process.env.ALLOWED_FRAME_URLS || ''}`]), - ], + headers, }, { source: '/share/:path*', - headers: [...headers, cspHeader()], + headers: shareHeaders, }, ]; }, diff --git a/package.json b/package.json index 08038ed7..5d8fff5e 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "npm-run-all": "^4.1.5", "prisma": "5.4.2", "react": "^18.2.0", - "react-basics": "^0.105.0", + "react-basics": "^0.106.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.4", @@ -125,9 +125,9 @@ "@rollup/plugin-replace": "^5.0.2", "@svgr/rollup": "^8.1.0", "@svgr/webpack": "^8.1.0", - "@types/node": "^18.11.9", - "@types/react": "^18.0.25", - "@types/react-dom": "^18.0.8", + "@types/node": "^20.9.0", + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.7.3", "cross-env": "^7.0.3", diff --git a/src/app/(main)/settings/websites/WebsiteAddForm.js b/src/app/(main)/settings/websites/WebsiteAddForm.tsx similarity index 76% rename from src/app/(main)/settings/websites/WebsiteAddForm.js rename to src/app/(main)/settings/websites/WebsiteAddForm.tsx index 371343ba..99624103 100644 --- a/src/app/(main)/settings/websites/WebsiteAddForm.js +++ b/src/app/(main)/settings/websites/WebsiteAddForm.tsx @@ -11,22 +11,22 @@ import useApi from 'components/hooks/useApi'; import { DOMAIN_REGEX } from 'lib/constants'; import useMessages from 'components/hooks/useMessages'; -export function WebsiteAddForm({ onSave, onClose }) { +export function WebsiteAddForm({ onSave, onClose }: { onSave?: () => void; onClose?: () => void }) { const { formatMessage, labels, messages } = useMessages(); const { post, useMutation } = useApi(); const { mutate, error, isLoading } = useMutation(data => post('/websites', data)); - const handleSubmit = async data => { + const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { - onSave(); - onClose(); + onSave?.(); + onClose?.(); }, }); }; return ( -
+ @@ -47,9 +47,11 @@ export function WebsiteAddForm({ onSave, onClose }) { {formatMessage(labels.save)} - + {onClose && ( + + )} ); diff --git a/src/components/common/ConfirmDeleteForm.js b/src/components/common/ConfirmDeleteForm.tsx similarity index 80% rename from src/components/common/ConfirmDeleteForm.js rename to src/components/common/ConfirmDeleteForm.tsx index 3d2c383d..d4cbf203 100644 --- a/src/components/common/ConfirmDeleteForm.js +++ b/src/components/common/ConfirmDeleteForm.tsx @@ -2,7 +2,13 @@ import { useState } from 'react'; import { Button, LoadingButton, Form, FormButtons } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; -export function ConfirmDeleteForm({ name, onConfirm, onClose }) { +export interface ConfirmDeleteFormProps { + name: string; + onConfirm?: () => void; + onClose?: () => void; +} + +export function ConfirmDeleteForm({ name, onConfirm, onClose }: ConfirmDeleteFormProps) { const [loading, setLoading] = useState(false); const { formatMessage, labels, messages, FormattedMessage } = useMessages(); diff --git a/src/components/common/Empty.tsx b/src/components/common/Empty.tsx index 2c7fcd4a..4e2677f8 100644 --- a/src/components/common/Empty.tsx +++ b/src/components/common/Empty.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; -import styles from './Empty.module.css'; import useMessages from 'components/hooks/useMessages'; +import styles from './Empty.module.css'; export interface EmptyProps { message?: string; diff --git a/src/components/common/EmptyPlaceholder.js b/src/components/common/EmptyPlaceholder.tsx similarity index 78% rename from src/components/common/EmptyPlaceholder.js rename to src/components/common/EmptyPlaceholder.tsx index 8834a1db..27282edc 100644 --- a/src/components/common/EmptyPlaceholder.js +++ b/src/components/common/EmptyPlaceholder.tsx @@ -1,6 +1,12 @@ +import { ReactNode } from 'react'; import { Icon, Text, Flexbox } from 'react-basics'; import Logo from 'assets/logo.svg'; +export interface EmptyPlaceholderProps { + message: string; + children?: ReactNode; +} + export function EmptyPlaceholder({ message, children }) { return ( diff --git a/src/components/common/ErrorBoundary.js b/src/components/common/ErrorBoundary.tsx similarity index 78% rename from src/components/common/ErrorBoundary.js rename to src/components/common/ErrorBoundary.tsx index 32cedb39..4eb2700f 100644 --- a/src/components/common/ErrorBoundary.js +++ b/src/components/common/ErrorBoundary.tsx @@ -1,14 +1,19 @@ /* eslint-disable no-console */ +import { ErrorInfo, ReactNode } from 'react'; import { ErrorBoundary as Boundary } from 'react-error-boundary'; import { Button } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; import styles from './ErrorBoundry.module.css'; -const logError = (error, info) => { +const logError = (error: Error, info: ErrorInfo) => { console.error(error, info.componentStack); }; -export function ErrorBoundary({ children }) { +export interface ErrorBoundaryProps { + children: ReactNode; +} + +export function ErrorBoundary({ children }: ErrorBoundaryProps) { const { formatMessage, messages } = useMessages(); const fallbackRender = ({ error, resetErrorBoundary }) => { diff --git a/src/components/common/ErrorMessage.js b/src/components/common/ErrorMessage.tsx similarity index 100% rename from src/components/common/ErrorMessage.js rename to src/components/common/ErrorMessage.tsx diff --git a/src/components/common/Favicon.js b/src/components/common/Favicon.tsx similarity index 93% rename from src/components/common/Favicon.js rename to src/components/common/Favicon.tsx index 55059cc0..2bf43c77 100644 --- a/src/components/common/Favicon.js +++ b/src/components/common/Favicon.tsx @@ -1,6 +1,6 @@ import styles from './Favicon.module.css'; -function getHostName(url) { +function getHostName(url: string) { const match = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:/\n?=]+)/im); return match && match.length > 1 ? match[1] : null; } diff --git a/src/components/common/FilterButtons.js b/src/components/common/FilterButtons.js deleted file mode 100644 index f5a54fb6..00000000 --- a/src/components/common/FilterButtons.js +++ /dev/null @@ -1,13 +0,0 @@ -import { ButtonGroup, Button, Flexbox } from 'react-basics'; - -export function FilterButtons({ items, selectedKey, onSelect }) { - return ( - - - {({ key, label }) => } - - - ); -} - -export default FilterButtons; diff --git a/src/components/common/FilterButtons.tsx b/src/components/common/FilterButtons.tsx new file mode 100644 index 00000000..e1860c78 --- /dev/null +++ b/src/components/common/FilterButtons.tsx @@ -0,0 +1,20 @@ +import { Key } from 'react'; +import { ButtonGroup, Button, Flexbox } from 'react-basics'; + +export interface FilterButtonsProps { + items: any[]; + selectedKey?: Key; + onSelect: () => void; +} + +export function FilterButtons({ items, selectedKey, onSelect }: FilterButtonsProps) { + return ( + + + {({ key, label }) => } + + + ); +} + +export default FilterButtons; diff --git a/src/components/common/FilterLink.js b/src/components/common/FilterLink.tsx similarity index 79% rename from src/components/common/FilterLink.js rename to src/components/common/FilterLink.tsx index 89648255..f91e1459 100644 --- a/src/components/common/FilterLink.js +++ b/src/components/common/FilterLink.tsx @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { Icon, Icons } from 'react-basics'; import classNames from 'classnames'; import Link from 'next/link'; @@ -6,7 +7,23 @@ import useNavigation from 'components/hooks/useNavigation'; import useMessages from 'components/hooks/useMessages'; import styles from './FilterLink.module.css'; -export function FilterLink({ id, value, label, externalUrl, children, className }) { +export interface FilterLinkProps { + id: string; + value: string; + label: string; + externalUrl: string; + className: string; + children: ReactNode; +} + +export function FilterLink({ + id, + value, + label, + externalUrl, + children, + className, +}: FilterLinkProps) { const { formatMessage, labels } = useMessages(); const { makeUrl, query } = useNavigation(); const active = query[id] !== undefined; diff --git a/src/components/common/LinkButton.js b/src/components/common/LinkButton.tsx similarity index 69% rename from src/components/common/LinkButton.js rename to src/components/common/LinkButton.tsx index a9a8562d..c9366e5c 100644 --- a/src/components/common/LinkButton.js +++ b/src/components/common/LinkButton.tsx @@ -2,8 +2,17 @@ import classNames from 'classnames'; import Link from 'next/link'; import { useLocale } from 'components/hooks'; import styles from './LinkButton.module.css'; +import { ReactNode } from 'react'; -export function LinkButton({ href, className, variant, scroll = true, children }) { +export interface LinkButtonProps { + href: string; + className: string; + variant?: string; + scroll?: boolean; + children?: ReactNode; +} + +export function LinkButton({ href, className, variant, scroll = true, children }: LinkButtonProps) { const { dir } = useLocale(); return ( diff --git a/yarn.lock b/yarn.lock index 6dd8b93b..da4ce1ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2393,10 +2393,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== -"@types/node@^18.11.9": - version "18.18.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.6.tgz#26da694f75cdb057750f49d099da5e3f3824cb3e" - integrity sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w== +"@types/node@^20.9.0": + version "20.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" + integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== + dependencies: + undici-types "~5.26.4" "@types/normalize-package-data@^2.4.0": version "2.4.3" @@ -2408,10 +2410,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== -"@types/react-dom@^18.0.8": - version "18.2.14" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.14.tgz#c01ba40e5bb57fc1dc41569bb3ccdb19eab1c539" - integrity sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ== +"@types/react-dom@^18.2.15": + version "18.2.15" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.15.tgz#921af67f9ee023ac37ea84b1bc0cc40b898ea522" + integrity sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg== dependencies: "@types/react" "*" @@ -2425,7 +2427,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@^18.0.25": +"@types/react@*", "@types/react@16 || 17 || 18": version "18.2.30" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.30.tgz#b84f786864fc46f18545364a54d5e1316308e59b" integrity sha512-OfqdJnDsSo4UNw0bqAjFCuBpLYQM7wvZidz0hVxHRjrEkzRlvZL1pJVyOSY55HMiKvRNEo9DUBRuEl7FNlJ/Vg== @@ -2434,6 +2436,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.2.37": + version "18.2.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.37.tgz#0f03af69e463c0f19a356c2660dbca5d19c44cae" + integrity sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" @@ -7455,10 +7466,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.105.0: - version "0.105.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.105.0.tgz#94eda703b3c0728e817b6e9d086e5d1c6c68f25c" - integrity sha512-iKYtfB0A2vsmO+X4jaX64XdmHE836w8TG2jFQ0pi5Qp0ktL0lAL9/q0IrWUjNr86hi0apg46aeJWxY+qQO+T1g== +react-basics@^0.106.0: + version "0.106.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.106.0.tgz#28ba95a06e6d36adcdb303e1556e6c731b505991" + integrity sha512-CD1qxFu4wrBeNubNo/SkBfWH0BuTErBueNJCCk04IC3qM9poUr3evYfs2S4sfql7dlorcOJ2GflKC1NJ8qPvmw== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1" @@ -8893,6 +8904,11 @@ undici-types@~5.25.1: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unenv@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.7.4.tgz#a0e5a78de2c7c3c4563c06ba9763c96c59db3333"