Skip to content

Commit

Permalink
Implement connector button and context menu action. (#7891)
Browse files Browse the repository at this point in the history
- Closes enso-org/cloud-v2#686

# Important Notes
For now they use the backend endpoints for secrets.
  • Loading branch information
somebody1234 authored Oct 2, 2023
1 parent b59e7c0 commit 3a010a0
Show file tree
Hide file tree
Showing 18 changed files with 197 additions and 53 deletions.
5 changes: 5 additions & 0 deletions app/ide-desktop/lib/assets/connector.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions app/ide-desktop/lib/assets/secret.svg

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import * as React from 'react'
import * as backendModule from '../backend'

import * as column from '../column'
import ConnectorNameColumn from './connectorNameColumn'
import DirectoryNameColumn from './directoryNameColumn'
import FileNameColumn from './fileNameColumn'
import ProjectNameColumn from './projectNameColumn'
import SecretNameColumn from './secretNameColumn'

// =================
// === AssetName ===
Expand All @@ -30,7 +30,7 @@ export default function AssetNameColumn(props: AssetNameColumnProps) {
return <FileNameColumn {...props} />
}
case backendModule.AssetType.secret: {
return <SecretNameColumn {...props} />
return <ConnectorNameColumn {...props} />
}
case backendModule.AssetType.specialLoading:
case backendModule.AssetType.specialEmpty: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export default function AssetRow(props: AssetRowProps) {
case assetEventModule.AssetEventType.newProject:
case assetEventModule.AssetEventType.newFolder:
case assetEventModule.AssetEventType.uploadFiles:
case assetEventModule.AssetEventType.newSecret:
case assetEventModule.AssetEventType.newDataConnector:
case assetEventModule.AssetEventType.openProject:
case assetEventModule.AssetEventType.closeProject:
case assetEventModule.AssetEventType.cancelOpeningAllProjects: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ export default function AssetsTable(props: AssetsTableProps) {
})
break
}
case assetListEventModule.AssetListEventType.newSecret: {
case assetListEventModule.AssetListEventType.newDataConnector: {
const placeholderItem: backendModule.SecretAsset = {
id: backendModule.SecretId(uniqueString.uniqueString()),
title: event.name,
Expand Down Expand Up @@ -854,7 +854,7 @@ export default function AssetsTable(props: AssetsTableProps) {
)
)
dispatchAssetEvent({
type: assetEventModule.AssetEventType.newSecret,
type: assetEventModule.AssetEventType.newDataConnector,
placeholderId: placeholderItem.id,
value: event.value,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import * as modalProvider from '../../providers/modal'

import Modal from './modal'

// =================
// === Component ===
// =================
// ==========================
// === ConfirmDeleteModal ===
// ==========================

/** Props for a {@link ConfirmDeleteModal}. */
export interface ConfirmDeleteModalProps {
Expand Down Expand Up @@ -61,19 +61,19 @@ export default function ConfirmDeleteModal(props: ConfirmDeleteModalProps) {
// delete an important asset.
onSubmit()
}}
className="relative shadow-soft rounded-2xl w-96 px-4 py-2"
className="relative flex flex-col rounded-2xl gap-2 w-96 px-4 p-2"
>
<div className="m-2">Are you sure you want to delete {description}?</div>
<div className="m-1">
<div>Are you sure you want to delete {description}?</div>
<div className="flex gap-2">
<button
type="submit"
className="hover:cursor-pointer inline-block text-white bg-delete rounded-full px-4 py-1 m-1"
className="hover:cursor-pointer inline-block text-white bg-delete rounded-full px-4 py-1"
>
Delete
</button>
<button
type="button"
className="hover:cursor-pointer inline-block bg-frame-selected rounded-full px-4 py-1 m-1"
className="hover:cursor-pointer inline-block bg-frame-selected rounded-full px-4 py-1"
onClick={unsetModal}
>
Cancel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file The icon and name of a {@link backendModule.SecretAsset}. */
import * as React from 'react'

import SecretIcon from 'enso-assets/secret.svg'
import ConnectorIcon from 'enso-assets/connector.svg'

import * as assetEventModule from '../events/assetEvent'
import * as assetListEventModule from '../events/assetListEvent'
Expand All @@ -17,19 +17,18 @@ import * as shortcutsProvider from '../../providers/shortcuts'

import * as column from '../column'
import EditableSpan from './editableSpan'
import SvgMask from '../../authentication/components/svgMask'

// ==================
// === SecretName ===
// ==================
// =====================
// === ConnectorName ===
// =====================

/** Props for a {@link SecretNameColumn}. */
export interface SecretNameColumnProps extends column.AssetColumnProps {}
/** Props for a {@link ConnectorNameColumn}. */
export interface ConnectorNameColumnProps extends column.AssetColumnProps {}

/** The icon and name of a {@link backendModule.SecretAsset}.
* @throws {Error} when the asset is not a {@link backendModule.SecretAsset}.
* This should never happen. */
export default function SecretNameColumn(props: SecretNameColumnProps) {
export default function ConnectorNameColumn(props: ConnectorNameColumnProps) {
const {
item,
setItem,
Expand All @@ -44,7 +43,7 @@ export default function SecretNameColumn(props: SecretNameColumnProps) {
const asset = item.item
if (asset.type !== backendModule.AssetType.secret) {
// eslint-disable-next-line no-restricted-syntax
throw new Error('`SecretNameColumn` can only display secret assets.')
throw new Error('`ConnectorNameColumn` can only display data connector assets.')
}
const setAsset = assetTreeNode.useSetAsset(asset, setItem)

Expand Down Expand Up @@ -72,10 +71,10 @@ export default function SecretNameColumn(props: SecretNameColumnProps) {
// `AssetRow`.
break
}
case assetEventModule.AssetEventType.newSecret: {
case assetEventModule.AssetEventType.newDataConnector: {
if (item.key === event.placeholderId) {
if (backend.type !== backendModule.BackendType.remote) {
toastAndLog('Secrets cannot be created on the local backend')
toastAndLog('Data connectors cannot be created on the local backend')
} else {
rowState.setPresence(presence.Presence.inserting)
try {
Expand All @@ -94,7 +93,7 @@ export default function SecretNameColumn(props: SecretNameColumnProps) {
type: assetListEventModule.AssetListEventType.delete,
key: item.key,
})
toastAndLog('Error creating new secret', error)
toastAndLog('Error creating new data connector', error)
}
}
}
Expand Down Expand Up @@ -126,7 +125,7 @@ export default function SecretNameColumn(props: SecretNameColumnProps) {
}
}}
>
<SvgMask src={SecretIcon} />
<img src={ConnectorIcon} className="m-1" />
<EditableSpan
editable={false}
onSubmit={async newTitle => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default function DirectoryNameColumn(props: DirectoryNameColumnProps) {
switch (event.type) {
case assetEventModule.AssetEventType.newProject:
case assetEventModule.AssetEventType.uploadFiles:
case assetEventModule.AssetEventType.newSecret:
case assetEventModule.AssetEventType.newDataConnector:
case assetEventModule.AssetEventType.openProject:
case assetEventModule.AssetEventType.closeProject:
case assetEventModule.AssetEventType.cancelOpeningAllProjects:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ export default function Drive(props: DriveProps) {
})
}, [/* should never change */ dispatchAssetListEvent])

const doCreateDataConnector = React.useCallback(
(name: string, value: string) => {
dispatchAssetListEvent({
type: assetListEventModule.AssetListEventType.newDataConnector,
parentKey: null,
parentId: null,
name,
value,
})
},
[/* should never change */ dispatchAssetListEvent]
)

React.useEffect(() => {
const onDragEnter = (event: DragEvent) => {
if (
Expand Down Expand Up @@ -176,6 +189,7 @@ export default function Drive(props: DriveProps) {
doCreateProject={doCreateProject}
doUploadFiles={doUploadFiles}
doCreateDirectory={doCreateDirectory}
doCreateDataConnector={doCreateDataConnector}
dispatchAssetEvent={dispatchAssetEvent}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as shortcutsProvider from '../../providers/shortcuts'

import * as categorySwitcher from './categorySwitcher'
import Button from './button'
import NewDataConnectorModal from './newDataConnectorModal'

// ================
// === DriveBar ===
Expand All @@ -26,17 +27,24 @@ export interface DriveBarProps {
category: categorySwitcher.Category
doCreateProject: (templateId: string | null) => void
doCreateDirectory: () => void
doCreateDataConnector: (name: string, value: string) => void
doUploadFiles: (files: File[]) => void
dispatchAssetEvent: (event: assetEventModule.AssetEvent) => void
}

/** Displays the current directory path and permissions, upload and download buttons,
* and a column display mode switcher. */
export default function DriveBar(props: DriveBarProps) {
const { category, doCreateProject, doCreateDirectory, doUploadFiles, dispatchAssetEvent } =
props
const {
category,
doCreateProject,
doCreateDirectory,
doCreateDataConnector,
doUploadFiles,
dispatchAssetEvent,
} = props
const { backend } = backendProvider.useBackend()
const { unsetModal } = modalProvider.useSetModal()
const { setModal, unsetModal } = modalProvider.useSetModal()
const { shortcuts } = shortcutsProvider.useShortcuts()
const uploadFilesRef = React.useRef<HTMLInputElement>(null)

Expand Down Expand Up @@ -98,16 +106,17 @@ export default function DriveBar(props: DriveBarProps) {
)}
{backend.type !== backendModule.BackendType.local && (
<Button
disabled
active
image={AddConnectorIcon}
error={
category === categorySwitcher.Category.trash
? 'Cannot create a new data connector in Trash.'
: 'Not implemented yet.'
}
disabledOpacityClassName="opacity-20"
onClick={() => {
// No backend support yet.
onClick={event => {
event.stopPropagation()
setModal(<NewDataConnectorModal doCreate={doCreateDataConnector} />)
}}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default function FileNameColumn(props: FileNameColumnProps) {
switch (event.type) {
case assetEventModule.AssetEventType.newProject:
case assetEventModule.AssetEventType.newFolder:
case assetEventModule.AssetEventType.newSecret:
case assetEventModule.AssetEventType.newDataConnector:
case assetEventModule.AssetEventType.openProject:
case assetEventModule.AssetEventType.closeProject:
case assetEventModule.AssetEventType.cancelOpeningAllProjects:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as shortcuts from '../shortcuts'

import ContextMenu from './contextMenu'
import MenuEntry from './menuEntry'
import NewDataConnectorModal from './newDataConnectorModal'

/** Props for a {@link GlobalContextMenu}. */
export interface GlobalContextMenuProps {
Expand All @@ -22,7 +23,7 @@ export interface GlobalContextMenuProps {
export default function GlobalContextMenu(props: GlobalContextMenuProps) {
const { hidden = false, directoryKey, directoryId, dispatchAssetListEvent } = props
const { backend } = backendProvider.useBackend()
const { unsetModal } = modalProvider.useSetModal()
const { setModal, unsetModal } = modalProvider.useSetModal()
const filesInputRef = React.useRef<HTMLInputElement>(null)
return (
<ContextMenu hidden={hidden}>
Expand Down Expand Up @@ -111,10 +112,22 @@ export default function GlobalContextMenu(props: GlobalContextMenuProps) {
{backend.type !== backendModule.BackendType.local && (
<MenuEntry
hidden={hidden}
disabled
action={shortcuts.KeyboardAction.newDataConnector}
doAction={() => {
// No backend support yet.
setModal(
<NewDataConnectorModal
doCreate={(name, value) => {
dispatchAssetListEvent({
type: assetListEventModule.AssetListEventType
.newDataConnector,
parentKey: directoryKey,
parentId: directoryId,
name,
value,
})
}}
/>
)
}}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface InputProps extends InputAttributes {
setValue: (value: string) => void
}

/** A component for authentication from inputs, with preset styles. */
/** A component for authentication form inputs, with preset styles. */
export default function Input(props: InputProps) {
const { setValue, error, validate = false, onChange, onBlur, ...passthroughProps } = props
const [reportTimeoutHandle, setReportTimeoutHandle] = React.useState<number | null>(null)
Expand Down
Loading

0 comments on commit 3a010a0

Please sign in to comment.