diff --git a/catalog/app/components/Dialog/Confirm.tsx b/catalog/app/components/Dialog/Confirm.tsx
index 5ccf067de4e..15d1749d709 100644
--- a/catalog/app/components/Dialog/Confirm.tsx
+++ b/catalog/app/components/Dialog/Confirm.tsx
@@ -3,13 +3,22 @@ import * as React from 'react'
import * as M from '@material-ui/core'
interface DialogProps {
+ cancelTitle?: string
children: React.ReactNode
onSubmit: (value: boolean) => void
open: boolean
+ submitTitle?: string
title: string
}
-function Dialog({ children, onSubmit, open, title }: DialogProps) {
+function Dialog({
+ children,
+ onSubmit,
+ open,
+ cancelTitle = 'Cancel',
+ submitTitle = 'Submit',
+ title,
+}: DialogProps) {
const handleCancel = React.useCallback(() => onSubmit(false), [onSubmit])
const handleSubmit = React.useCallback(() => onSubmit(true), [onSubmit])
return (
@@ -18,10 +27,10 @@ function Dialog({ children, onSubmit, open, title }: DialogProps) {
{children}
- Cancel
+ {cancelTitle}
- Submit
+ {submitTitle}
@@ -29,11 +38,13 @@ function Dialog({ children, onSubmit, open, title }: DialogProps) {
}
interface PromptProps {
+ cancelTitle?: string
onSubmit: (value: boolean) => void
+ submitTitle?: string
title: string
}
-export function useConfirm({ title, onSubmit }: PromptProps) {
+export function useConfirm({ cancelTitle, title, onSubmit, submitTitle }: PromptProps) {
const [key, setKey] = React.useState(0)
const [opened, setOpened] = React.useState(false)
const open = React.useCallback(() => {
@@ -52,15 +63,17 @@ export function useConfirm({ title, onSubmit }: PromptProps) {
(children: React.ReactNode) => (
),
- [key, handleSubmit, opened, title],
+ [cancelTitle, key, handleSubmit, opened, title, submitTitle],
)
return React.useMemo(
() => ({
diff --git a/catalog/app/containers/Admin/Buckets/Buckets.tsx b/catalog/app/containers/Admin/Buckets/Buckets.tsx
index d1bc9322765..32efc35c696 100644
--- a/catalog/app/containers/Admin/Buckets/Buckets.tsx
+++ b/catalog/app/containers/Admin/Buckets/Buckets.tsx
@@ -11,6 +11,7 @@ import * as M from '@material-ui/core'
import * as Lab from '@material-ui/lab'
import BucketIcon from 'components/BucketIcon'
+import * as Dialog from 'components/Dialog'
import * as Pagination from 'components/Pagination'
import Skeleton from 'components/Skeleton'
import * as Notifications from 'containers/Notifications'
@@ -81,6 +82,66 @@ const integerInRange = (min: number, max: number) => (v: string | null | undefin
return undefined
}
+const usePFSCheckboxStyles = M.makeStyles({
+ root: {
+ marginBottom: -9,
+ marginTop: -9,
+ },
+})
+function PFSCheckbox({ input, meta }: Form.CheckboxProps & M.CheckboxProps) {
+ const classes = usePFSCheckboxStyles()
+ const confirm = React.useCallback((checked) => input?.onChange(checked), [input])
+ const dialog = Dialog.useConfirm({
+ submitTitle: 'I agree',
+ title:
+ 'You are about to enable JavaScript execution and data access in iframe previews of HTML files',
+ onSubmit: confirm,
+ })
+ const handleCheckbox = React.useCallback(
+ (event, checked: boolean) => {
+ if (checked) {
+ dialog.open()
+ } else {
+ input?.onChange(checked)
+ }
+ },
+ [dialog, input],
+ )
+ return (
+ <>
+ {dialog.render(
+
+ Warning: you must only enable this feature for buckets with trusted contents.
+ Failure to heed this warning may result in breach of sensitive data.
+ ,
+ )}
+
+ }
+ label={
+ <>
+ Enable permissive HTML rendering
+
+ This allows execution of any linked JavaScript code and fetching network
+ resources relative to the package. Be aware that the iframe with rendered
+ HTML (and package resources) can be shared publicly during the session
+ lifespan. The session is active while the page with rendered HTML is open.
+
+ Enable only on trusted AWS S3 buckets.
+
+ >
+ }
+ />
+ >
+ )
+}
+
const editFormSpec: FormSpec = {
title: R.pipe(
R.prop('title'),
@@ -648,24 +709,7 @@ function BucketFields({ bucket, reindex }: BucketFieldsProps) {
File preview options
-
- Enable permissive HTML rendering
-
- This allows execution of any JavaScript code and fetching network
- resources relative to package. But beware, the iframe with rendered HTML
- (and package resources) can be shared publicly during session lifespan.
- Session is active while the page with rendered HTML is opened.
-
- Enable only on trusted buckets.
-
- >
- }
- />
+
diff --git a/catalog/app/containers/Admin/Form.tsx b/catalog/app/containers/Admin/Form.tsx
index 1a6da17bcaf..2d9e8ccb66a 100644
--- a/catalog/app/containers/Admin/Form.tsx
+++ b/catalog/app/containers/Admin/Form.tsx
@@ -36,11 +36,11 @@ const useCheckboxStyles = M.makeStyles({
},
})
-interface CheckboxProps {
+export interface CheckboxProps {
errors?: Record
input?: RF.FieldInputProps
meta: RF.FieldMetaState
- label?: string
+ label?: React.ReactNode
FormControlLabelProps?: M.FormControlLabelProps
}
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index eb5639227a6..f0f8157b8bc 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -22,6 +22,7 @@ Entries inside each section should be ordered by type:
* [Added] Add basic support for tasklist in Markdown ([#3339](https://github.com/quiltdata/quilt/pull/3339))
* [Added] Object-level validation, frontend ([#3336](https://github.com/quiltdata/quilt/pull/3336))
* [Added] Frontend for permissive HTML rendering ([#3198](https://github.com/quiltdata/quilt/pull/3198))
+* [Added] Confirmation to enable Package Files Server ([#3388](https://github.com/quiltdata/quilt/pull/3388))
* [Fixed] Fixed mobile layout for collaborators badges ([#3307](https://github.com/quiltdata/quilt/pull/3307))
* [Fixed] Fixed metadata handling for entries without hash or size in pkgpush lambda ([#3314](https://github.com/quiltdata/quilt/pull/3314))
* [Fixed] Fixed adding metadata for S3 entries ([#3367]https://github.com/quiltdata/quilt/pull/3367)