mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 10:05:06 +03:00
Dashboard fixes (#9467)
- Close https://github.com/enso-org/cloud-v2/issues/1037 - Fix downloading files. The issue was that the S3 domain was not whitelisted. - Fix #9345 - Fix https://github.com/enso-org/cloud-v2/issues/1012 - Make "Update" button in assets panel (right panel) disabled until its value is updated. # Important Notes None
This commit is contained in:
parent
4379df7c2d
commit
3505893390
@ -15,6 +15,7 @@ const TRUSTED_HOSTS = [
|
||||
'production-enso-domain.auth.eu-west-1.amazoncognito.com',
|
||||
'production-enso-organizations-files.s3.amazonaws.com',
|
||||
'pb-enso-domain.auth.eu-west-1.amazoncognito.com',
|
||||
's3.eu-west-1.amazonaws.com',
|
||||
// This (`localhost`) is required to access Project Manager HTTP endpoints.
|
||||
// This should be changed appropriately if the Project Manager's port number becomes dynamic.
|
||||
'127.0.0.1:30535',
|
||||
|
@ -66,6 +66,7 @@ import Subscribe from '#/pages/subscribe/Subscribe'
|
||||
import type Backend from '#/services/Backend'
|
||||
import LocalBackend from '#/services/LocalBackend'
|
||||
|
||||
import * as eventModule from '#/utilities/event'
|
||||
import LocalStorage from '#/utilities/LocalStorage'
|
||||
import * as object from '#/utilities/object'
|
||||
|
||||
@ -267,12 +268,7 @@ function AppRouter(props: AppProps) {
|
||||
isClick = true
|
||||
}
|
||||
const onMouseUp = (event: MouseEvent) => {
|
||||
if (
|
||||
isClick &&
|
||||
!(event.target instanceof HTMLInputElement) &&
|
||||
!(event.target instanceof HTMLTextAreaElement) &&
|
||||
!(event.target instanceof HTMLElement && event.target.isContentEditable)
|
||||
) {
|
||||
if (isClick && !eventModule.isElementTextInput(event.target)) {
|
||||
const selection = document.getSelection()
|
||||
const app = document.getElementById('app')
|
||||
const appContainsSelection =
|
||||
|
@ -158,7 +158,8 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
|
||||
readOnly={readOnly}
|
||||
checked={typeof value === 'boolean' && value}
|
||||
onChange={event => {
|
||||
setValue(event.currentTarget.checked)
|
||||
const newValue: boolean = event.currentTarget.checked
|
||||
setValue(newValue)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
@ -240,7 +241,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
|
||||
// This is SAFE; but there is no way to tell TypeScript that an object
|
||||
// has an index signature.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
(oldValue as Record<string, unknown>)[key] === newValue
|
||||
(oldValue as Readonly<Record<string, unknown>>)[key] === newValue
|
||||
? oldValue
|
||||
: { ...oldValue, [key]: newValue }
|
||||
)
|
||||
@ -300,7 +301,6 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
|
||||
setSelectedChildIndex(index)
|
||||
const newConstantValue = jsonSchema.constantValue(defs, childSchema, true)
|
||||
setValue(newConstantValue[0] ?? null)
|
||||
setSelectedChildIndex(index)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import * as animationHooks from '#/hooks/animationHooks'
|
||||
|
||||
import * as modalProvider from '#/providers/ModalProvider'
|
||||
|
||||
import * as eventModule from '#/utilities/event'
|
||||
import type * as geometry from '#/utilities/geometry'
|
||||
|
||||
// ======================
|
||||
@ -63,9 +64,7 @@ export default function SelectionBrush(props: SelectionBrushProps) {
|
||||
const onMouseDown = (event: MouseEvent) => {
|
||||
if (
|
||||
modalRef.current == null &&
|
||||
!(event.target instanceof HTMLInputElement) &&
|
||||
!(event.target instanceof HTMLTextAreaElement) &&
|
||||
(!(event.target instanceof HTMLElement) || !event.target.isContentEditable) &&
|
||||
!eventModule.isElementTextInput(event.target) &&
|
||||
!(event.target instanceof HTMLButtonElement) &&
|
||||
!(event.target instanceof HTMLAnchorElement)
|
||||
) {
|
||||
|
@ -51,7 +51,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
|
||||
const [description, setDescription] = React.useState('')
|
||||
const [dataLinkValue, setDataLinkValue] = React.useState<NonNullable<unknown> | null>(null)
|
||||
const [editedDataLinkValue, setEditedDataLinkValue] = React.useState<NonNullable<unknown> | null>(
|
||||
null
|
||||
dataLinkValue
|
||||
)
|
||||
const [isDataLinkFetched, setIsDataLinkFetched] = React.useState(false)
|
||||
const isDataLinkSubmittable = React.useMemo(
|
||||
@ -75,6 +75,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
|
||||
self?.permission === permissions.PermissionAction.admin ||
|
||||
self?.permission === permissions.PermissionAction.edit
|
||||
const isDataLink = item.item.type === backendModule.AssetType.dataLink
|
||||
const isDataLinkDisabled = dataLinkValue === editedDataLinkValue || !isDataLinkSubmittable
|
||||
|
||||
React.useEffect(() => {
|
||||
setDescription(item.item.description ?? '')
|
||||
@ -85,7 +86,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
|
||||
if (item.item.type === backendModule.AssetType.dataLink) {
|
||||
const value = await backend.getConnector(item.item.id, item.item.title)
|
||||
setDataLinkValue(value)
|
||||
setEditedDataLinkValue(structuredClone(value))
|
||||
setEditedDataLinkValue(value)
|
||||
setIsDataLinkFetched(true)
|
||||
}
|
||||
})()
|
||||
@ -231,8 +232,11 @@ export default function AssetProperties(props: AssetPropertiesProps) {
|
||||
<div className="flex gap-buttons">
|
||||
<button
|
||||
type="button"
|
||||
disabled={dataLinkValue === editedDataLinkValue || !isDataLinkSubmittable}
|
||||
className="button bg-invite text-white selectable enabled:active"
|
||||
disabled={isDataLinkDisabled}
|
||||
{...(isDataLinkDisabled
|
||||
? { title: 'Edit the Data Link before updating it.' }
|
||||
: {})}
|
||||
className="button bg-invite text-white enabled:active"
|
||||
onClick={() => {
|
||||
void (async () => {
|
||||
if (item.item.type === backendModule.AssetType.dataLink) {
|
||||
@ -258,9 +262,10 @@ export default function AssetProperties(props: AssetPropertiesProps) {
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="button bg-selected-frame"
|
||||
disabled={isDataLinkDisabled}
|
||||
className="button bg-selected-frame enabled:active"
|
||||
onClick={() => {
|
||||
setEditedDataLinkValue(structuredClone(dataLinkValue))
|
||||
setEditedDataLinkValue(dataLinkValue)
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
|
@ -170,9 +170,7 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
}
|
||||
// Allow `alt` key to be pressed in case it is being used to enter special characters.
|
||||
if (
|
||||
!(event.target instanceof HTMLInputElement) &&
|
||||
!(event.target instanceof HTMLTextAreaElement) &&
|
||||
(!(event.target instanceof HTMLElement) || !event.target.isContentEditable) &&
|
||||
!eventModule.isElementTextInput(event.target) &&
|
||||
(!(event.target instanceof Node) || rootRef.current?.contains(event.target) !== true) &&
|
||||
eventModule.isTextInputEvent(event) &&
|
||||
event.key !== ' ' &&
|
||||
|
@ -122,6 +122,12 @@ export default function AccountSettingsTab() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-non-null-assertion
|
||||
accessToken != null ? JSON.parse(atob(accessToken.split('.')[1]!)).username : null
|
||||
const canChangePassword = username != null ? !/^Github_|^Google_/.test(username) : false
|
||||
const canSubmitPassword =
|
||||
currentPassword !== '' &&
|
||||
newPassword !== '' &&
|
||||
confirmNewPassword !== '' &&
|
||||
newPassword === confirmNewPassword &&
|
||||
validation.PASSWORD_REGEX.test(newPassword)
|
||||
|
||||
const doUpdateName = async (newName: string) => {
|
||||
const oldName = user?.name ?? ''
|
||||
@ -231,14 +237,8 @@ export default function AccountSettingsTab() {
|
||||
</div>
|
||||
<div className="flex h-row items-center gap-buttons">
|
||||
<button
|
||||
disabled={
|
||||
currentPassword === '' ||
|
||||
newPassword === '' ||
|
||||
confirmNewPassword === '' ||
|
||||
newPassword !== confirmNewPassword ||
|
||||
!validation.PASSWORD_REGEX.test(newPassword)
|
||||
}
|
||||
type="submit"
|
||||
disabled={!canSubmitPassword}
|
||||
className={`settings-value rounded-full bg-invite font-medium text-white selectable enabled:active`}
|
||||
onClick={() => {
|
||||
setPasswordFormKey(uniqueString.uniqueString())
|
||||
@ -252,7 +252,8 @@ export default function AccountSettingsTab() {
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="settings-value rounded-full bg-selected-frame font-medium"
|
||||
disabled={!canSubmitPassword}
|
||||
className="settings-value rounded-full bg-selected-frame font-medium selectable enabled:active"
|
||||
onClick={() => {
|
||||
setPasswordFormKey(uniqueString.uniqueString())
|
||||
setCurrentPassword('')
|
||||
|
@ -50,3 +50,13 @@ export function isTextInputEvent(event: KeyboardEvent | React.KeyboardEvent) {
|
||||
// Allow `alt` key to be pressed in case it is being used to enter special characters.
|
||||
return !event.ctrlKey && !event.shiftKey && !event.metaKey && isTextInputKey(event)
|
||||
}
|
||||
|
||||
/** Whether the element accepts text input. */
|
||||
export function isElementTextInput(element: EventTarget | null) {
|
||||
return (
|
||||
element != null &&
|
||||
(element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement ||
|
||||
(element instanceof HTMLElement && element.isContentEditable))
|
||||
)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
* shortcuts. */
|
||||
import * as detect from 'enso-common/src/detect'
|
||||
|
||||
import * as eventModule from '#/utilities/event'
|
||||
import * as newtype from '#/utilities/newtype'
|
||||
import * as object from '#/utilities/object'
|
||||
import * as string from '#/utilities/string'
|
||||
@ -552,7 +553,10 @@ export function defineBindingNamespace<T extends Record<keyof T, KeybindValue>>(
|
||||
: buttonToPointerButtonFlags(event.button)
|
||||
]?.[eventModifierFlags]
|
||||
let handle = handlers[DEFAULT_HANDLER]
|
||||
if (matchingBindings != null) {
|
||||
const isTextInputFocused = eventModule.isElementTextInput(document.activeElement)
|
||||
const isTextInputEvent = 'key' in event && eventModule.isTextInputEvent(event)
|
||||
const shouldIgnoreEvent = isTextInputFocused && isTextInputEvent
|
||||
if (matchingBindings != null && !shouldIgnoreEvent) {
|
||||
for (const bindingNameRaw in handlers) {
|
||||
// This is SAFE, because `handlers` is an object with identical keys to `T`,
|
||||
// which `BindingName` is also derived from.
|
||||
|
Loading…
Reference in New Issue
Block a user