Rename Connector to Datalinks (#9948)

#### Tl;dr
Closes: enso-org/cloud-v2#1132
This PR renames Connector to Datalink

---

#### Test Plan:
Everything should work as before,  but instead of sending `connectorId` we send `dataLinkId` and endpoint now is `/datalink`

---
This commit is contained in:
Sergei Garin 2024-05-20 11:45:55 +03:00 committed by GitHub
parent c7476c10f3
commit 55d43a3d8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 229 additions and 229 deletions

2
.github/CODEOWNERS vendored
View File

@ -47,5 +47,5 @@ Cargo.toml
# Dashboard, Cloud & Authentication
/app/ide-desktop/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
# The data-link schema is owned by the libraries team
/app/ide-desktop/lib/dashboard/src/data/dataLinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley
/app/ide-desktop/lib/dashboard/src/data/datalinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley
/app/ide-desktop/lib/dashboard/src/data/__tests__ @radeusgd @jdunkerley @GregoryTravis @AdRiley @PabloBuchu @indiv0 @somebody1234

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 625 B

View File

@ -83,7 +83,7 @@ export function locateSecretValueInput(page: test.Page) {
/** Find a search bar input (if any) on the current page. */
export function locateSearchBarInput(page: test.Page) {
return locateSearchBar(page).getByPlaceholder(
'Type to search for projects, Data Links, users, and more.'
'Type to search for projects, Datalinks, users, and more.'
)
}

View File

@ -1,4 +1,4 @@
/** @file A dynamic wizard for creating an arbitrary type of Data Link. */
/** @file A dynamic wizard for creating an arbitrary type of Datalink. */
import * as React from 'react'
import * as backendProvider from '#/providers/BackendProvider'
@ -31,7 +31,7 @@ export interface JSONSchemaInputProps {
readonly setValue: React.Dispatch<React.SetStateAction<NonNullable<unknown> | null>>
}
/** A dynamic wizard for creating an arbitrary type of Data Link. */
/** A dynamic wizard for creating an arbitrary type of Datalink. */
export default function JSONSchemaInput(props: JSONSchemaInputProps) {
const { dropdownTitle, readOnly = false, defs, schema, path, getValidator } = props
const { value: valueRaw, setValue: setValueRaw } = props

View File

@ -43,7 +43,7 @@ const ACTION_TO_TEXT_ID: Readonly<Record<inputBindings.DashboardBindingKey, text
uploadFiles: 'uploadFilesShortcut',
newProject: 'newProjectShortcut',
newFolder: 'newFolderShortcut',
newDataLink: 'newDataLinkShortcut',
newDatalink: 'newDatalinkShortcut',
newSecret: 'newSecretShortcut',
useInNewProject: 'useInNewProjectShortcut',
closeModal: 'closeModalShortcut',

View File

@ -2,7 +2,7 @@
import * as React from 'react'
import BlankIcon from 'enso-assets/blank.svg'
import ConnectorIcon from 'enso-assets/connector.svg'
import DatalinkIcon from 'enso-assets/datalink.svg'
import FolderIcon from 'enso-assets/folder.svg'
import KeyIcon from 'enso-assets/key.svg'
import NetworkIcon from 'enso-assets/network.svg'
@ -32,8 +32,8 @@ export default function AssetIcon(props: AssetIconProps) {
case backend.AssetType.file: {
return <SvgMask src={fileIcon.fileIcon()} className={className} />
}
case backend.AssetType.dataLink: {
return <SvgMask src={ConnectorIcon} className={className} />
case backend.AssetType.datalink: {
return <SvgMask src={DatalinkIcon} className={className} />
}
case backend.AssetType.secret: {
return <SvgMask src={KeyIcon} className={className} />

View File

@ -230,7 +230,7 @@ export default function AssetRow(props: AssetRowProps) {
}
case backendModule.AssetType.project:
case backendModule.AssetType.secret:
case backendModule.AssetType.dataLink:
case backendModule.AssetType.datalink:
case backendModule.AssetType.specialLoading:
case backendModule.AssetType.specialEmpty: {
// Ignored.
@ -422,7 +422,7 @@ export default function AssetRow(props: AssetRowProps) {
case AssetEventType.newProject:
case AssetEventType.newFolder:
case AssetEventType.uploadFiles:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.newSecret:
case AssetEventType.updateFiles:
case AssetEventType.openProject:
@ -509,9 +509,9 @@ export default function AssetRow(props: AssetRowProps) {
}
break
}
case backendModule.AssetType.dataLink: {
case backendModule.AssetType.datalink: {
try {
const value = await backend.getConnector(asset.id, asset.title)
const value = await backend.getDatalink(asset.id, asset.title)
const fileName = `${asset.title}.datalink`
download.download(
URL.createObjectURL(
@ -522,7 +522,7 @@ export default function AssetRow(props: AssetRowProps) {
fileName
)
} catch (error) {
toastAndLog('downloadDataLinkError', error, asset.title)
toastAndLog('downloadDatalinkError', error, asset.title)
}
break
}
@ -687,7 +687,7 @@ export default function AssetRow(props: AssetRowProps) {
case backendModule.AssetType.directory:
case backendModule.AssetType.project:
case backendModule.AssetType.file:
case backendModule.AssetType.dataLink:
case backendModule.AssetType.datalink:
case backendModule.AssetType.secret: {
const innerProps: AssetRowInnerProps = {
key,

View File

@ -1,8 +1,8 @@
/** @file A dynamic wizard for creating an arbitrary type of Data Link. */
/** @file A dynamic wizard for creating an arbitrary type of Datalink. */
import * as React from 'react'
import SCHEMA from '#/data/dataLinkSchema.json' assert { type: 'json' }
import * as dataLinkValidator from '#/data/dataLinkValidator'
import SCHEMA from '#/data/datalinkSchema.json' assert { type: 'json' }
import * as datalinkValidator from '#/data/datalinkValidator'
import type * as jsonSchemaInput from '#/components/JSONSchemaInput'
import JSONSchemaInput from '#/components/JSONSchemaInput'
@ -22,19 +22,19 @@ const DEFS: Record<string, object> = SCHEMA.$defs
/** Get a known schema using a path.
* @throws {Error} when there is no schema present at the given path. */
function getValidator(path: string) {
return error.assert<(value: unknown) => boolean>(() => dataLinkValidator.AJV.getSchema(path))
return error.assert<(value: unknown) => boolean>(() => datalinkValidator.AJV.getSchema(path))
}
// =====================
// === DataLinkInput ===
// =====================
/** Props for a {@link DataLinkInput}. */
export interface DataLinkInputProps
/** Props for a {@link DatalinkInput}. */
export interface DatalinkInputProps
extends Omit<jsonSchemaInput.JSONSchemaInputProps, 'defs' | 'getValidator' | 'path' | 'schema'> {}
/** A dynamic wizard for creating an arbitrary type of Data Link. */
export default function DataLinkInput(props: DataLinkInputProps) {
/** A dynamic wizard for creating an arbitrary type of Datalink. */
export default function DatalinkInput(props: DatalinkInputProps) {
return (
<JSONSchemaInput
defs={DEFS}

View File

@ -1,7 +1,7 @@
/** @file The icon and name of a {@link backendModule.SecretAsset}. */
import * as React from 'react'
import ConnectorIcon from 'enso-assets/connector.svg'
import DatalinkIcon from 'enso-assets/datalink.svg'
import * as eventHooks from '#/hooks/eventHooks'
import * as setAssetHooks from '#/hooks/setAssetHooks'
@ -23,25 +23,25 @@ import * as indent from '#/utilities/indent'
import * as object from '#/utilities/object'
import Visibility from '#/utilities/Visibility'
// =====================
// === ConnectorName ===
// =====================
// ====================
// === DatalinkName ===
// ====================
/** Props for a {@link DataLinkNameColumn}. */
export interface DataLinkNameColumnProps extends column.AssetColumnProps {}
/** Props for a {@link DatalinkNameColumn}. */
export interface DatalinkNameColumnProps extends column.AssetColumnProps {}
/** The icon and name of a {@link backendModule.DataLinkAsset}.
* @throws {Error} when the asset is not a {@link backendModule.DataLinkAsset}.
/** The icon and name of a {@link backendModule.DatalinkAsset}.
* @throws {Error} when the asset is not a {@link backendModule.DatalinkAsset}.
* This should never happen. */
export default function DataLinkNameColumn(props: DataLinkNameColumnProps) {
export default function DatalinkNameColumn(props: DatalinkNameColumnProps) {
const { item, setItem, selected, state, rowState, setRowState, isEditable } = props
const { assetEvents, dispatchAssetListEvent, setIsAssetPanelTemporarilyVisible } = state
const toastAndLog = toastAndLogHooks.useToastAndLog()
const { backend } = backendProvider.useBackend()
const inputBindings = inputBindingsProvider.useInputBindings()
if (item.type !== backendModule.AssetType.dataLink) {
if (item.type !== backendModule.AssetType.datalink) {
// eslint-disable-next-line no-restricted-syntax
throw new Error('`DataLinkNameColumn` can only display Data Links.')
throw new Error('`DatalinkNameColumn` can only display Datalinks.')
}
const asset = item.item
const setAsset = setAssetHooks.useSetAsset(asset, setItem)
@ -90,16 +90,16 @@ export default function DataLinkNameColumn(props: DataLinkNameColumnProps) {
// are handled by `AssetRow`.
break
}
case AssetEventType.newDataLink: {
case AssetEventType.newDatalink: {
if (item.key === event.placeholderId) {
if (backend.type !== backendModule.BackendType.remote) {
toastAndLog('localBackendDataLinkError')
toastAndLog('localBackendDatalinkError')
} else {
rowState.setVisibility(Visibility.faded)
try {
const { id } = await backend.createConnector({
const { id } = await backend.createDatalink({
parentDirectoryId: asset.parentId,
connectorId: null,
datalinkId: null,
name: asset.title,
value: event.value,
})
@ -107,7 +107,7 @@ export default function DataLinkNameColumn(props: DataLinkNameColumnProps) {
setAsset(object.merger({ id }))
} catch (error) {
dispatchAssetListEvent({ type: AssetListEventType.delete, key: item.key })
toastAndLog('createDataLinkError', error)
toastAndLog('createDatalinkError', error)
}
}
}
@ -145,7 +145,7 @@ export default function DataLinkNameColumn(props: DataLinkNameColumnProps) {
}
}}
>
<img src={ConnectorIcon} className="m-name-column-icon size-icon" />
<img src={DatalinkIcon} className="m-name-column-icon size-icon" />
<EditableSpan
editable={false}
onSubmit={async newTitle => {

View File

@ -83,7 +83,7 @@ export default function DirectoryNameColumn(props: DirectoryNameColumnProps) {
switch (event.type) {
case AssetEventType.newProject:
case AssetEventType.uploadFiles:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.newSecret:
case AssetEventType.openProject:
case AssetEventType.updateFiles:

View File

@ -81,7 +81,7 @@ export default function FileNameColumn(props: FileNameColumnProps) {
switch (event.type) {
case AssetEventType.newProject:
case AssetEventType.newFolder:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.newSecret:
case AssetEventType.openProject:
case AssetEventType.closeProject:

View File

@ -25,9 +25,9 @@ const ASSET_TYPE_TO_TEXT_ID: Readonly<Record<backendModule.AssetType, text.TextI
[backendModule.AssetType.project]: 'projectAssetType',
[backendModule.AssetType.file]: 'fileAssetType',
[backendModule.AssetType.secret]: 'secretAssetType',
[backendModule.AssetType.dataLink]: 'connectorAssetType',
[backendModule.AssetType.specialEmpty]: 'specialEmptyAssetType',
[backendModule.AssetType.specialLoading]: 'specialLoadingAssetType',
[backendModule.AssetType.datalink]: 'datalinkAssetType',
} satisfies { [Type in backendModule.AssetType]: `${Type}AssetType` }
// ==================

View File

@ -17,7 +17,7 @@ const CAPITALIZED_ASSET_TYPE: Readonly<Record<backend.AssetType, string>> = {
[backend.AssetType.directory]: 'Folder',
[backend.AssetType.project]: 'Project',
[backend.AssetType.file]: 'File',
[backend.AssetType.dataLink]: 'Data Link',
[backend.AssetType.datalink]: 'Datalink',
[backend.AssetType.secret]: 'Secret',
// These assets should never be visible, since they don't have columns.
[backend.AssetType.specialEmpty]: 'Empty asset',

View File

@ -236,7 +236,7 @@ export default function ProjectIcon(props: ProjectIconProps) {
switch (event.type) {
case AssetEventType.newFolder:
case AssetEventType.uploadFiles:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.newSecret:
case AssetEventType.copy:
case AssetEventType.updateFiles:

View File

@ -110,7 +110,7 @@ export default function ProjectNameColumn(props: ProjectNameColumnProps) {
async event => {
switch (event.type) {
case AssetEventType.newFolder:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.newSecret:
case AssetEventType.openProject:
case AssetEventType.closeProject:

View File

@ -65,7 +65,7 @@ export default function SecretNameColumn(props: SecretNameColumnProps) {
case AssetEventType.newProject:
case AssetEventType.newFolder:
case AssetEventType.uploadFiles:
case AssetEventType.newDataLink:
case AssetEventType.newDatalink:
case AssetEventType.openProject:
case AssetEventType.updateFiles:
case AssetEventType.closeProject:

View File

@ -2,7 +2,7 @@
import * as React from 'react'
import type * as column from '#/components/dashboard/column'
import DataLinkNameColumn from '#/components/dashboard/DataLinkNameColumn'
import DatalinkNameColumn from '#/components/dashboard/DatalinkNameColumn'
import DirectoryNameColumn from '#/components/dashboard/DirectoryNameColumn'
import FileNameColumn from '#/components/dashboard/FileNameColumn'
import ProjectNameColumn from '#/components/dashboard/ProjectNameColumn'
@ -30,8 +30,8 @@ export default function AssetNameColumn(props: AssetNameColumnProps) {
case backendModule.AssetType.file: {
return <FileNameColumn {...props} />
}
case backendModule.AssetType.dataLink: {
return <DataLinkNameColumn {...props} />
case backendModule.AssetType.datalink: {
return <DatalinkNameColumn {...props} />
}
case backendModule.AssetType.secret: {
return <SecretNameColumn {...props} />

View File

@ -1,6 +1,6 @@
/** @file Shortcuts for the dashboard application. */
import AddConnectorIcon from 'enso-assets/add_connector.svg'
import AddDatalinkIcon from 'enso-assets/add_datalink.svg'
import AddFolderIcon from 'enso-assets/add_folder.svg'
import AddKeyIcon from 'enso-assets/add_key.svg'
import AddNetworkIcon from 'enso-assets/add_network.svg'
@ -81,10 +81,10 @@ export const BINDINGS = inputBindings.defineBindings({
bindings: !detect.isOnMacOS() ? ['Mod+Alt+N'] : ['Mod+Alt+N', 'Mod+Alt+~'],
icon: AddKeyIcon,
},
newDataLink: {
name: 'New Data Link',
newDatalink: {
name: 'New Datalink',
bindings: !detect.isOnMacOS() ? ['Mod+Alt+Shift+N'] : ['Mod+Alt+Shift+N', 'Mod+Alt+Shift+~'],
icon: AddConnectorIcon,
icon: AddDatalinkIcon,
},
useInNewProject: {
name: 'Use In New Project',

View File

@ -6,23 +6,23 @@ import * as url from 'node:url'
import * as v from 'vitest'
import * as dataLinkValidator from '#/data/dataLinkValidator'
import * as datalinkValidator from '#/data/datalinkValidator'
v.test('correctly rejects invalid values as not matching the schema', () => {
v.expect(dataLinkValidator.validateDataLink({})).toBe(false)
v.expect(dataLinkValidator.validateDataLink('foobar')).toBe(false)
v.expect(dataLinkValidator.validateDataLink({ foo: 'BAR' })).toBe(false)
v.expect(datalinkValidator.validateDatalink({})).toBe(false)
v.expect(datalinkValidator.validateDatalink('foobar')).toBe(false)
v.expect(datalinkValidator.validateDatalink({ foo: 'BAR' })).toBe(false)
})
/** Load and parse a data-link description. */
function loadDataLinkFile(dataLinkPath: string): unknown {
const text: string = fs.readFileSync(dataLinkPath, { encoding: 'utf-8' })
function loadDataLinkFile(datalinkPath: string): unknown {
const text: string = fs.readFileSync(datalinkPath, { encoding: 'utf-8' })
return JSON.parse(text)
}
/** Check if the given data-link description matches the schema, reporting any errors. */
function testSchema(json: unknown, fileName: string): void {
const validate = dataLinkValidator.validateDataLink
const validate = datalinkValidator.validateDatalink
if (!validate(json)) {
v.assert.fail(`Failed to validate ${fileName}:\n${JSON.stringify(validate.errors, null, 2)}`)
}
@ -60,7 +60,7 @@ v.test('rejects invalid schemas (Base)', () => {
const invalidSchemas = ['example-http-format-invalid.datalink']
for (const schema of invalidSchemas) {
const json = loadDataLinkFile(path.resolve(BASE_DATA_LINKS_ROOT, schema))
v.expect(dataLinkValidator.validateDataLink(json)).toBe(false)
v.expect(datalinkValidator.validateDatalink(json)).toBe(false)
}
})

View File

@ -1,8 +1,8 @@
/** @file AJV instance configured for data links. */
/** @file AJV instance configured for datalinks. */
import type * as ajv from 'ajv/dist/2020'
import Ajv from 'ajv/dist/2020'
import SCHEMA from '#/data/dataLinkSchema.json' assert { type: 'json' }
import SCHEMA from '#/data/datalinkSchema.json' assert { type: 'json' }
import * as error from '#/utilities/error'
@ -12,6 +12,6 @@ AJV.addSchema(SCHEMA)
// This is a function, even though it does not contain function syntax.
// eslint-disable-next-line no-restricted-syntax
export const validateDataLink = error.assert<ajv.ValidateFunction>(() =>
export const validateDatalink = error.assert<ajv.ValidateFunction>(() =>
AJV.getSchema('#/$defs/DataLink')
)

View File

@ -10,7 +10,7 @@ enum AssetEventType {
newFolder = 'new-folder',
uploadFiles = 'upload-files',
updateFiles = 'update-files',
newDataLink = 'new-data-link',
newDatalink = 'new-datalink',
newSecret = 'new-secret',
openProject = 'open-project',
closeProject = 'close-project',

View File

@ -5,7 +5,7 @@ enum AssetListEventType {
newFolder = 'new-folder',
newProject = 'new-project',
uploadFiles = 'upload-files',
newDataLink = 'new-data-link',
newDatalink = 'new-datalink',
newSecret = 'new-secret',
insertAssets = 'insert-assets',
closeFolder = 'close-folder',

View File

@ -29,7 +29,7 @@ interface AssetEvents {
readonly newFolder: AssetNewFolderEvent
readonly uploadFiles: AssetUploadFilesEvent
readonly updateFiles: AssetUpdateFilesEvent
readonly newDataLink: AssetNewDataLinkEvent
readonly newDatalink: AssetNewDatalinkEvent
readonly newSecret: AssetNewSecretEvent
readonly openProject: AssetOpenProjectEvent
readonly closeProject: AssetCloseProjectEvent
@ -63,7 +63,7 @@ type SanityCheck<
export interface AssetNewProjectEvent extends AssetBaseEvent<AssetEventType.newProject> {
readonly placeholderId: backend.ProjectId
readonly templateId: string | null
readonly datalinkId: backend.ConnectorId | null
readonly datalinkId: backend.DatalinkId | null
readonly onSpinnerStateChange: ((state: spinner.SpinnerState) => void) | null
}
@ -82,9 +82,9 @@ export interface AssetUpdateFilesEvent extends AssetBaseEvent<AssetEventType.upd
readonly files: ReadonlyMap<backend.AssetId, File>
}
/** A signal to create a Data Link. */
export interface AssetNewDataLinkEvent extends AssetBaseEvent<AssetEventType.newDataLink> {
readonly placeholderId: backend.ConnectorId
/** A signal to create a Datalink. */
export interface AssetNewDatalinkEvent extends AssetBaseEvent<AssetEventType.newDatalink> {
readonly placeholderId: backend.DatalinkId
readonly value: unknown
}

View File

@ -29,7 +29,7 @@ interface AssetListEvents {
readonly newProject: AssetListNewProjectEvent
readonly uploadFiles: AssetListUploadFilesEvent
readonly newSecret: AssetListNewSecretEvent
readonly newDataLink: AssetListNewDataLinkEvent
readonly newDatalink: AssetListNewDatalinkEvent
readonly insertAssets: AssetListInsertAssetsEvent
readonly closeFolder: AssetListCloseFolderEvent
readonly copy: AssetListCopyEvent
@ -62,7 +62,7 @@ interface AssetListNewProjectEvent extends AssetListBaseEvent<AssetListEventType
readonly parentKey: backend.DirectoryId
readonly parentId: backend.DirectoryId
readonly templateId: string | null
readonly datalinkId: backend.ConnectorId | null
readonly datalinkId: backend.DatalinkId | null
readonly preferredName: string | null
readonly onSpinnerStateChange: ((state: spinner.SpinnerState) => void) | null
}
@ -75,7 +75,7 @@ interface AssetListUploadFilesEvent extends AssetListBaseEvent<AssetListEventTyp
}
/** A signal to create a new secret. */
interface AssetListNewDataLinkEvent extends AssetListBaseEvent<AssetListEventType.newDataLink> {
interface AssetListNewDatalinkEvent extends AssetListBaseEvent<AssetListEventType.newDatalink> {
readonly parentKey: backend.DirectoryId
readonly parentId: backend.DirectoryId
readonly name: string

View File

@ -129,7 +129,7 @@ export default function AssetContextMenu(props: AssetContextMenuProps) {
) : (
<ContextMenus hidden={hidden} key={asset.id} event={event}>
<ContextMenu aria-label={getText('assetContextMenuLabel')} hidden={hidden}>
{asset.type === backendModule.AssetType.dataLink && (
{asset.type === backendModule.AssetType.datalink && (
<ContextMenuEntry
hidden={hidden}
action="useInNewProject"
@ -377,7 +377,7 @@ export default function AssetContextMenu(props: AssetContextMenuProps) {
isDisabled={
isCloud &&
asset.type !== backendModule.AssetType.file &&
asset.type !== backendModule.AssetType.dataLink &&
asset.type !== backendModule.AssetType.datalink &&
asset.type !== backendModule.AssetType.project
}
action="download"

View File

@ -3,7 +3,7 @@ import * as React from 'react'
import PenIcon from 'enso-assets/pen.svg'
import * as dataLinkValidator from '#/data/dataLinkValidator'
import * as datalinkValidator from '#/data/datalinkValidator'
import * as toastAndLogHooks from '#/hooks/toastAndLogHooks'
@ -17,7 +17,7 @@ import type Category from '#/layouts/CategorySwitcher/Category'
import * as aria from '#/components/aria'
import SharedWithColumn from '#/components/dashboard/column/SharedWithColumn'
import DataLinkInput from '#/components/dashboard/DataLinkInput'
import DatalinkInput from '#/components/dashboard/DatalinkInput'
import Label from '#/components/dashboard/Label'
import StatelessSpinner, * as statelessSpinner from '#/components/StatelessSpinner'
import Button from '#/components/styled/Button'
@ -65,14 +65,14 @@ export default function AssetProperties(props: AssetPropertiesProps) {
const [isEditingDescription, setIsEditingDescription] = React.useState(false)
const [queuedDescription, setQueuedDescripion] = React.useState<string | null>(null)
const [description, setDescription] = React.useState('')
const [dataLinkValue, setDataLinkValue] = React.useState<NonNullable<unknown> | null>(null)
const [editedDataLinkValue, setEditedDataLinkValue] = React.useState<NonNullable<unknown> | null>(
dataLinkValue
const [datalinkValue, setDatalinkValue] = React.useState<NonNullable<unknown> | null>(null)
const [editedDatalinkValue, setEditedDatalinkValue] = React.useState<NonNullable<unknown> | null>(
datalinkValue
)
const [isDataLinkFetched, setIsDataLinkFetched] = React.useState(false)
const isDataLinkSubmittable = React.useMemo(
() => dataLinkValidator.validateDataLink(dataLinkValue),
[dataLinkValue]
const [isDatalinkFetched, setIsDatalinkFetched] = React.useState(false)
const isDatalinkSubmittable = React.useMemo(
() => datalinkValidator.validateDatalink(datalinkValue),
[datalinkValue]
)
const setItem = React.useCallback(
(valueOrUpdater: React.SetStateAction<assetTreeNode.AnyAssetTreeNode>) => {
@ -89,8 +89,8 @@ export default function AssetProperties(props: AssetPropertiesProps) {
ownsThisAsset ||
self?.permission === permissions.PermissionAction.admin ||
self?.permission === permissions.PermissionAction.edit
const isDataLink = item.item.type === backendModule.AssetType.dataLink
const isDataLinkDisabled = dataLinkValue === editedDataLinkValue || !isDataLinkSubmittable
const isDatalink = item.item.type === backendModule.AssetType.datalink
const isDatalinkDisabled = datalinkValue === editedDatalinkValue || !isDatalinkSubmittable
React.useEffect(() => {
setDescription(item.item.description ?? '')
@ -98,11 +98,11 @@ export default function AssetProperties(props: AssetPropertiesProps) {
React.useEffect(() => {
void (async () => {
if (item.item.type === backendModule.AssetType.dataLink) {
const value = await backend.getConnector(item.item.id, item.item.title)
setDataLinkValue(value)
setEditedDataLinkValue(value)
setIsDataLinkFetched(true)
if (item.item.type === backendModule.AssetType.datalink) {
const value = await backend.getDatalink(item.item.id, item.item.title)
setDatalinkValue(value)
setEditedDatalinkValue(value)
setIsDatalinkFetched(true)
}
})()
}, [backend, item.item])
@ -239,50 +239,50 @@ export default function AssetProperties(props: AssetPropertiesProps) {
</tbody>
</table>
</div>
{isDataLink && (
{isDatalink && (
<div className="pointer-events-auto flex flex-col items-start gap-side-panel-section">
<aria.Heading
level={2}
className="h-side-panel-heading py-side-panel-heading-y text-lg leading-snug"
>
{getText('dataLink')}
{getText('datalink')}
</aria.Heading>
{!isDataLinkFetched ? (
{!isDatalinkFetched ? (
<div className="grid place-items-center self-stretch">
<StatelessSpinner size={48} state={statelessSpinner.SpinnerState.loadingMedium} />
</div>
) : (
<>
<DataLinkInput
<DatalinkInput
readOnly={!canEditThisAsset}
dropdownTitle="Type"
value={editedDataLinkValue}
setValue={setEditedDataLinkValue}
value={editedDatalinkValue}
setValue={setEditedDatalinkValue}
/>
{canEditThisAsset && (
<div className="flex gap-buttons">
<UnstyledButton
isDisabled={isDataLinkDisabled}
{...(isDataLinkDisabled
? { title: 'Edit the Data Link before updating it.' }
isDisabled={isDatalinkDisabled}
{...(isDatalinkDisabled
? { title: 'Edit the Datalink before updating it.' }
: {})}
className="button bg-invite text-white enabled:active"
onPress={() => {
void (async () => {
if (item.item.type === backendModule.AssetType.dataLink) {
const oldDataLinkValue = dataLinkValue
if (item.item.type === backendModule.AssetType.datalink) {
const oldDatalinkValue = datalinkValue
try {
setDataLinkValue(editedDataLinkValue)
await backend.createConnector({
connectorId: item.item.id,
setDatalinkValue(editedDatalinkValue)
await backend.createDatalink({
datalinkId: item.item.id,
name: item.item.title,
parentDirectoryId: null,
value: editedDataLinkValue,
value: editedDatalinkValue,
})
} catch (error) {
toastAndLog(null, error)
setDataLinkValue(oldDataLinkValue)
setEditedDataLinkValue(oldDataLinkValue)
setDatalinkValue(oldDatalinkValue)
setEditedDatalinkValue(oldDatalinkValue)
}
}
})()
@ -291,10 +291,10 @@ export default function AssetProperties(props: AssetPropertiesProps) {
{getText('update')}
</UnstyledButton>
<UnstyledButton
isDisabled={isDataLinkDisabled}
isDisabled={isDatalinkDisabled}
className="button bg-selected-frame enabled:active"
onPress={() => {
setEditedDataLinkValue(dataLinkValue)
setEditedDatalinkValue(datalinkValue)
}}
>
{getText('cancel')}

View File

@ -181,9 +181,9 @@ const SUGGESTIONS_FOR_NEGATIVE_TYPE: assetSearchBar.Suggestion[] = [
deleteFromQuery: query => query.deleteFromLastTerm({ negativeTypes: ['file'] }),
},
{
render: () => 'type:connector',
addToQuery: query => query.addToLastTerm({ negativeTypes: ['connector'] }),
deleteFromQuery: query => query.deleteFromLastTerm({ negativeTypes: ['connector'] }),
render: () => 'type:datalink',
addToQuery: query => query.addToLastTerm({ negativeTypes: ['datalink'] }),
deleteFromQuery: query => query.deleteFromLastTerm({ negativeTypes: ['datalink'] }),
},
]
@ -232,7 +232,7 @@ function insertArbitraryAssetTreeNodeChildren(
[backendModule.AssetType.directory]: [],
[backendModule.AssetType.project]: [],
[backendModule.AssetType.file]: [],
[backendModule.AssetType.dataLink]: [],
[backendModule.AssetType.datalink]: [],
[backendModule.AssetType.secret]: [],
[backendModule.AssetType.specialLoading]: [],
[backendModule.AssetType.specialEmpty]: [],
@ -449,7 +449,7 @@ export default function AssetsTable(props: AssetsTableProps) {
const assetType =
node.item.type === backendModule.AssetType.directory
? 'folder'
: node.item.type === backendModule.AssetType.dataLink
: node.item.type === backendModule.AssetType.datalink
? 'datalink'
: String(node.item.type)
const assetExtension =
@ -918,7 +918,7 @@ export default function AssetsTable(props: AssetsTableProps) {
return (
node?.item.type === backendModule.AssetType.project ||
node?.item.type === backendModule.AssetType.file ||
node?.item.type === backendModule.AssetType.dataLink
node?.item.type === backendModule.AssetType.datalink
)
})
)
@ -1230,7 +1230,7 @@ export default function AssetsTable(props: AssetsTableProps) {
})
break
}
case backendModule.AssetType.dataLink: {
case backendModule.AssetType.datalink: {
event.preventDefault()
event.stopPropagation()
setIsAssetPanelTemporarilyVisible(true)
@ -1653,10 +1653,10 @@ export default function AssetsTable(props: AssetsTableProps) {
}
break
}
case AssetListEventType.newDataLink: {
const placeholderItem: backendModule.DataLinkAsset = {
type: backendModule.AssetType.dataLink,
id: backendModule.ConnectorId(uniqueString.uniqueString()),
case AssetListEventType.newDatalink: {
const placeholderItem: backendModule.DatalinkAsset = {
type: backendModule.AssetType.datalink,
id: backendModule.DatalinkId(uniqueString.uniqueString()),
title: event.name,
modifiedAt: dateTime.toRfc3339(new Date()),
parentId: event.parentId,
@ -1668,7 +1668,7 @@ export default function AssetsTable(props: AssetsTableProps) {
doToggleDirectoryExpansion(event.parentId, event.parentKey, null, true)
insertAssets([placeholderItem], event.parentKey, event.parentId)
dispatchAssetEvent({
type: AssetEventType.newDataLink,
type: AssetEventType.newDatalink,
placeholderId: placeholderItem.id,
value: event.value,
})

View File

@ -285,10 +285,10 @@ export default function Drive(props: DriveProps) {
[rootDirectoryId, /* should never change */ dispatchAssetListEvent]
)
const doCreateDataLink = React.useCallback(
const doCreateDatalink = React.useCallback(
(name: string, value: unknown) => {
dispatchAssetListEvent({
type: AssetListEventType.newDataLink,
type: AssetListEventType.newDatalink,
parentKey: targetDirectoryNodeRef.current?.key ?? rootDirectoryId,
parentId: targetDirectoryNodeRef.current?.item.id ?? rootDirectoryId,
name,
@ -377,7 +377,7 @@ export default function Drive(props: DriveProps) {
doUploadFiles={doUploadFiles}
doCreateDirectory={doCreateDirectory}
doCreateSecret={doCreateSecret}
doCreateDataLink={doCreateDataLink}
doCreateDatalink={doCreateDatalink}
dispatchAssetEvent={dispatchAssetEvent}
/>
</div>

View File

@ -2,7 +2,7 @@
* the current directory and some configuration options. */
import * as React from 'react'
import AddConnectorIcon from 'enso-assets/add_connector.svg'
import AddDatalinkIcon from 'enso-assets/add_datalink.svg'
import AddFolderIcon from 'enso-assets/add_folder.svg'
import AddKeyIcon from 'enso-assets/add_key.svg'
import DataDownloadIcon from 'enso-assets/data_download.svg'
@ -24,7 +24,7 @@ import HorizontalMenuBar from '#/components/styled/HorizontalMenuBar'
import UnstyledButton from '#/components/UnstyledButton'
import ConfirmDeleteModal from '#/modals/ConfirmDeleteModal'
import UpsertDataLinkModal from '#/modals/UpsertDataLinkModal'
import UpsertDatalinkModal from '#/modals/UpsertDatalinkModal'
import UpsertSecretModal from '#/modals/UpsertSecretModal'
import * as backendModule from '#/services/Backend'
@ -43,7 +43,7 @@ export interface DriveBarProps {
readonly doCreateProject: () => void
readonly doCreateDirectory: () => void
readonly doCreateSecret: (name: string, value: string) => void
readonly doCreateDataLink: (name: string, value: unknown) => void
readonly doCreateDatalink: (name: string, value: unknown) => void
readonly doUploadFiles: (files: File[]) => void
readonly dispatchAssetEvent: (event: assetEvent.AssetEvent) => void
}
@ -52,7 +52,7 @@ export interface DriveBarProps {
* and a column display mode switcher. */
export default function DriveBar(props: DriveBarProps) {
const { category, canDownload, doEmptyTrash, doCreateProject, doCreateDirectory } = props
const { doCreateSecret, doCreateDataLink, doUploadFiles, dispatchAssetEvent } = props
const { doCreateSecret, doCreateDatalink, doUploadFiles, dispatchAssetEvent } = props
const { backend } = backendProvider.useBackend()
const { setModal, unsetModal } = modalProvider.useSetModal()
const { getText } = textProvider.useText()
@ -150,10 +150,10 @@ export default function DriveBar(props: DriveBarProps) {
{isCloud && (
<Button
active
image={AddConnectorIcon}
alt={getText('newDataLink')}
image={AddDatalinkIcon}
alt={getText('newDatalink')}
onPress={() => {
setModal(<UpsertDataLinkModal doCreate={doCreateDataLink} />)
setModal(<UpsertDatalinkModal doCreate={doCreateDatalink} />)
}}
/>
)}

View File

@ -12,7 +12,7 @@ import * as aria from '#/components/aria'
import ContextMenu from '#/components/ContextMenu'
import ContextMenuEntry from '#/components/ContextMenuEntry'
import UpsertDataLinkModal from '#/modals/UpsertDataLinkModal'
import UpsertDatalinkModal from '#/modals/UpsertDatalinkModal'
import UpsertSecretModal from '#/modals/UpsertSecretModal'
import * as backendModule from '#/services/Backend'
@ -145,13 +145,13 @@ export default function GlobalContextMenu(props: GlobalContextMenuProps) {
{isCloud && (
<ContextMenuEntry
hidden={hidden}
action="newDataLink"
action="newDatalink"
doAction={() => {
setModal(
<UpsertDataLinkModal
<UpsertDatalinkModal
doCreate={(name, value) => {
dispatchAssetListEvent({
type: AssetListEventType.newDataLink,
type: AssetListEventType.newDatalink,
parentKey: directoryKey ?? rootDirectoryId,
parentId: directoryId ?? rootDirectoryId,
name,

View File

@ -1,14 +1,14 @@
/** @file A modal for creating a Data Link. */
/** @file A modal for creating a Datalink. */
import * as React from 'react'
import SCHEMA from '#/data/dataLinkSchema.json' assert { type: 'json' }
import * as dataLinkValidator from '#/data/dataLinkValidator'
import SCHEMA from '#/data/datalinkSchema.json' assert { type: 'json' }
import * as datalinkValidator from '#/data/datalinkValidator'
import * as modalProvider from '#/providers/ModalProvider'
import * as textProvider from '#/providers/TextProvider'
import * as aria from '#/components/aria'
import DataLinkInput from '#/components/dashboard/DataLinkInput'
import DatalinkInput from '#/components/dashboard/DatalinkInput'
import Modal from '#/components/Modal'
import ButtonRow from '#/components/styled/ButtonRow'
import FocusArea from '#/components/styled/FocusArea'
@ -22,26 +22,26 @@ import * as jsonSchema from '#/utilities/jsonSchema'
// =================
const DEFS: Record<string, object> = SCHEMA.$defs
const INITIAL_DATA_LINK_VALUE =
const INITIAL_DATALINK_VALUE =
jsonSchema.constantValue(DEFS, SCHEMA.$defs.DataLink, true)[0] ?? null
// ===========================
// === UpsertDataLinkModal ===
// ===========================
/** Props for a {@link UpsertDataLinkModal}. */
export interface UpsertDataLinkModalProps {
readonly doCreate: (name: string, dataLink: unknown) => void
/** Props for a {@link UpsertDatalinkModal}. */
export interface UpsertDatalinkModalProps {
readonly doCreate: (name: string, datalink: unknown) => void
}
/** A modal for creating a Data Link. */
export default function UpsertDataLinkModal(props: UpsertDataLinkModalProps) {
/** A modal for creating a Datalink. */
export default function UpsertDatalinkModal(props: UpsertDatalinkModalProps) {
const { doCreate } = props
const { unsetModal } = modalProvider.useSetModal()
const { getText } = textProvider.useText()
const [name, setName] = React.useState('')
const [value, setValue] = React.useState<NonNullable<unknown> | null>(INITIAL_DATA_LINK_VALUE)
const isValueSubmittable = React.useMemo(() => dataLinkValidator.validateDataLink(value), [value])
const [value, setValue] = React.useState<NonNullable<unknown> | null>(INITIAL_DATALINK_VALUE)
const isValueSubmittable = React.useMemo(() => datalinkValidator.validateDatalink(value), [value])
const isSubmittable = name !== '' && isValueSubmittable
const doSubmit = () => {
@ -62,7 +62,7 @@ export default function UpsertDataLinkModal(props: UpsertDataLinkModalProps) {
}}
>
<aria.Heading className="relative text-sm font-semibold">
{getText('createDataLink')}
{getText('createDatalink')}
</aria.Heading>
<FocusArea direction="horizontal">
{innerProps => (
@ -75,7 +75,7 @@ export default function UpsertDataLinkModal(props: UpsertDataLinkModalProps) {
<FocusRing>
<aria.Input
autoFocus
placeholder={getText('dataLinkNamePlaceholder')}
placeholder={getText('datalinkNamePlaceholder')}
className={`focus-child text grow rounded-full border bg-transparent px-input-x ${
name !== '' ? 'border-primary/10' : 'border-red-700/60'
}`}
@ -89,7 +89,7 @@ export default function UpsertDataLinkModal(props: UpsertDataLinkModalProps) {
)}
</FocusArea>
<div className="relative">
<DataLinkInput dropdownTitle="Type" value={value} setValue={setValue} />
<DatalinkInput dropdownTitle="Type" value={value} setValue={setValue} />
</div>
<ButtonRow>
<UnstyledButton

View File

@ -51,9 +51,9 @@ export const FileId = newtype.newtypeConstructor<FileId>()
export type SecretId = newtype.Newtype<string, 'SecretId'>
export const SecretId = newtype.newtypeConstructor<SecretId>()
/** Unique identifier for a Data Link. */
export type ConnectorId = newtype.Newtype<string, 'ConnectorId'>
export const ConnectorId = newtype.newtypeConstructor<ConnectorId>()
/** Unique identifier for a Datalink. */
export type DatalinkId = newtype.Newtype<string, 'DatalinkId'>
export const DatalinkId = newtype.newtypeConstructor<DatalinkId>()
/** Unique identifier for an arbitrary asset. */
export type AssetId = IdType[keyof IdType]
@ -340,12 +340,12 @@ export interface SecretInfo {
readonly path: string
}
/** A Data Link. */
export type Connector = newtype.Newtype<unknown, 'Connector'>
/** A Datalink. */
export type Datalink = newtype.Newtype<unknown, 'Datalink'>
/** Metadata uniquely identifying a Data Link. */
export interface ConnectorInfo {
readonly id: ConnectorId
/** Metadata uniquely identifying a Datalink. */
export interface DatalinkInfo {
readonly id: DatalinkId
}
/** A label. */
@ -655,7 +655,7 @@ export enum AssetType {
project = 'project',
file = 'file',
secret = 'secret',
dataLink = 'connector',
datalink = 'datalink',
directory = 'directory',
/** A special {@link AssetType} representing the unknown items of a directory, before the
* request to retrieve the items completes. */
@ -668,7 +668,7 @@ export enum AssetType {
export interface IdType {
readonly [AssetType.project]: ProjectId
readonly [AssetType.file]: FileId
readonly [AssetType.dataLink]: ConnectorId
readonly [AssetType.datalink]: DatalinkId
readonly [AssetType.secret]: SecretId
readonly [AssetType.directory]: DirectoryId
readonly [AssetType.specialLoading]: LoadingAssetId
@ -684,7 +684,7 @@ export const ASSET_TYPE_ORDER: Readonly<Record<AssetType, number>> = {
[AssetType.directory]: 0,
[AssetType.project]: 1,
[AssetType.file]: 2,
[AssetType.dataLink]: 3,
[AssetType.datalink]: 3,
[AssetType.secret]: 4,
[AssetType.specialLoading]: 999,
[AssetType.specialEmpty]: 1000,
@ -726,8 +726,8 @@ export interface ProjectAsset extends Asset<AssetType.project> {}
/** A convenience alias for {@link Asset}<{@link AssetType.file}>. */
export interface FileAsset extends Asset<AssetType.file> {}
/** A convenience alias for {@link Asset}<{@link AssetType.dataLink}>. */
export interface DataLinkAsset extends Asset<AssetType.dataLink> {}
/** A convenience alias for {@link Asset}<{@link AssetType.datalink}>. */
export interface DatalinkAsset extends Asset<AssetType.datalink> {}
/** A convenience alias for {@link Asset}<{@link AssetType.secret}>. */
export interface SecretAsset extends Asset<AssetType.secret> {}
@ -838,7 +838,7 @@ interface HasType<Type extends AssetType> {
/** A union of all possible {@link Asset} variants. */
export type AnyAsset<Type extends AssetType = AssetType> = Extract<
| DataLinkAsset
| DatalinkAsset
| DirectoryAsset
| FileAsset
| ProjectAsset
@ -875,8 +875,8 @@ export function createPlaceholderAssetId<Type extends AssetType>(
result = FileId(id)
break
}
case AssetType.dataLink: {
result = ConnectorId(id)
case AssetType.datalink: {
result = DatalinkId(id)
break
}
case AssetType.secret: {
@ -903,8 +903,8 @@ export function createPlaceholderAssetId<Type extends AssetType>(
export const assetIsProject = assetIsType(AssetType.project)
/** A type guard that returns whether an {@link Asset} is a {@link DirectoryAsset}. */
export const assetIsDirectory = assetIsType(AssetType.directory)
/** A type guard that returns whether an {@link Asset} is a {@link DataLinkAsset}. */
export const assetIsDataLink = assetIsType(AssetType.dataLink)
/** A type guard that returns whether an {@link Asset} is a {@link DatalinkAsset}. */
export const assetIsDatalink = assetIsType(AssetType.datalink)
/** A type guard that returns whether an {@link Asset} is a {@link SecretAsset}. */
export const assetIsSecret = assetIsType(AssetType.secret)
/** A type guard that returns whether an {@link Asset} is a {@link FileAsset}. */
@ -1034,7 +1034,7 @@ export interface CreateProjectRequestBody {
readonly projectName: string
readonly projectTemplateName?: string
readonly parentDirectoryId?: DirectoryId
readonly datalinkId?: ConnectorId
readonly datalinkId?: DatalinkId
}
/** HTTP request body for the "update project" endpoint.
@ -1068,12 +1068,12 @@ export interface UpdateSecretRequestBody {
readonly value: string
}
/** HTTP request body for the "create connector" endpoint. */
export interface CreateConnectorRequestBody {
/** HTTP request body for the "create datalink" endpoint. */
export interface CreateDatalinkRequestBody {
readonly name: string
readonly value: unknown
readonly parentDirectoryId: DirectoryId | null
readonly connectorId: ConnectorId | null
readonly datalinkId: DatalinkId | null
}
/** HTTP request body for the "create tag" endpoint. */
@ -1320,12 +1320,12 @@ export default abstract class Backend {
abstract updateFile(fileId: FileId, body: UpdateFileRequestBody, title: string): Promise<void>
/** Return file details. */
abstract getFileDetails(fileId: FileId, title: string): Promise<FileDetails>
/** Create a Data Link. */
abstract createConnector(body: CreateConnectorRequestBody): Promise<ConnectorInfo>
/** Return a Data Link. */
abstract getConnector(connectorId: ConnectorId, title: string | null): Promise<Connector>
/** Delete a Data Link. */
abstract deleteConnector(connectorId: ConnectorId, title: string | null): Promise<void>
/** Create a Datalink. */
abstract createDatalink(body: CreateDatalinkRequestBody): Promise<DatalinkInfo>
/** Return a Datalink. */
abstract getDatalink(datalinkId: DatalinkId, title: string | null): Promise<Datalink>
/** Delete a Datalink. */
abstract deleteDatalink(datalinkId: DatalinkId, title: string | null): Promise<void>
/** Create a secret environment variable. */
abstract createSecret(body: CreateSecretRequestBody): Promise<SecretId>
/** Return a secret environment variable. */

View File

@ -621,17 +621,17 @@ export default class LocalBackend extends Backend {
}
/** Invalid operation. */
override createConnector() {
override createDatalink() {
return this.invalidOperation()
}
/** Invalid operation. */
override getConnector() {
override getDatalink() {
return this.invalidOperation()
}
/** Invalid operation. */
override deleteConnector() {
override deleteDatalink() {
return this.invalidOperation()
}

View File

@ -732,42 +732,42 @@ export default class RemoteBackend extends Backend {
}
}
/** Return a Data Link.
/** Return a Datalink.
* @throws An error if a non-successful status code (not 200-299) was received. */
override async createConnector(
body: backend.CreateConnectorRequestBody
): Promise<backend.ConnectorInfo> {
const path = remoteBackendPaths.CREATE_CONNECTOR_PATH
const response = await this.post<backend.ConnectorInfo>(path, body)
override async createDatalink(
body: backend.CreateDatalinkRequestBody
): Promise<backend.DatalinkInfo> {
const path = remoteBackendPaths.CREATE_DATALINK_PATH
const response = await this.post<backend.DatalinkInfo>(path, body)
if (!responseIsSuccessful(response)) {
return await this.throw(response, 'createConnectorBackendError', body.name)
return await this.throw(response, 'createDatalinkBackendError', body.name)
} else {
return await response.json()
}
}
/** Return a Data Link.
/** Return a Datalink.
* @throws An error if a non-successful status code (not 200-299) was received. */
override async getConnector(
connectorId: backend.ConnectorId,
override async getDatalink(
datalinkId: backend.DatalinkId,
title: string
): Promise<backend.Connector> {
const path = remoteBackendPaths.getConnectorPath(connectorId)
const response = await this.get<backend.Connector>(path)
): Promise<backend.Datalink> {
const path = remoteBackendPaths.getDatalinkPath(datalinkId)
const response = await this.get<backend.Datalink>(path)
if (!responseIsSuccessful(response)) {
return await this.throw(response, 'getConnectorBackendError', title)
return await this.throw(response, 'getDatalinkBackendError', title)
} else {
return await response.json()
}
}
/** Delete a Data Link.
/** Delete a Datalink.
* @throws An error if a non-successful status code (not 200-299) was received. */
override async deleteConnector(connectorId: backend.ConnectorId, title: string): Promise<void> {
const path = remoteBackendPaths.getConnectorPath(connectorId)
override async deleteDatalink(datalinkId: backend.DatalinkId, title: string): Promise<void> {
const path = remoteBackendPaths.getDatalinkPath(datalinkId)
const response = await this.delete(path)
if (!responseIsSuccessful(response)) {
return await this.throw(response, 'deleteConnectorBackendError', title)
return await this.throw(response, 'deleteDatalinkBackendError', title)
} else {
return
}

View File

@ -47,8 +47,8 @@ export const UPLOAD_FILE_PATH = 'files'
export const CREATE_SECRET_PATH = 'secrets'
/** Relative HTTP path to the "list secrets" endpoint of the Cloud backend API. */
export const LIST_SECRETS_PATH = 'secrets'
/** Relative HTTP path to the "create connector" endpoint of the Cloud backend API. */
export const CREATE_CONNECTOR_PATH = 'connectors'
/** Relative HTTP path to the "create datalink" endpoint of the Cloud backend API. */
export const CREATE_DATALINK_PATH = 'datalinks'
/** Relative HTTP path to the "create tag" endpoint of the Cloud backend API. */
export const CREATE_TAG_PATH = 'tags'
/** Relative HTTP path to the "list tags" endpoint of the Cloud backend API. */
@ -125,9 +125,9 @@ export function updateSecretPath(secretId: backend.SecretId) {
export function getSecretPath(secretId: backend.SecretId) {
return `secrets/${secretId}`
}
/** Relative HTTP path to the "get connector" endpoint of the Cloud backend API. */
export function getConnectorPath(connectorId: backend.ConnectorId) {
return `connectors/${connectorId}`
/** Relative HTTP path to the "get datalink" endpoint of the Cloud backend API. */
export function getDatalinkPath(datalinkId: backend.DatalinkId) {
return `datalinks/${datalinkId}`
}
/** Relative HTTP path to the "associate tag" endpoint of the Cloud backend API. */
export function associateTagPath(assetId: backend.AssetId) {

View File

@ -96,7 +96,7 @@
--context-menu-macos-width: 14.375rem;
--context-menu-entry-padding-x: 0.75rem;
--separator-margin-y: 0.125rem;
/* The vertical gap between entries in a Data Link input. */
/* The vertical gap between entries in a Datalink input. */
--json-schema-gap: 0.25rem;
--json-schema-text-input-width: 10rem;
--json-schema-object-input-padding: 0.5rem;

View File

@ -2,7 +2,7 @@
"submit": "Submit",
"createFolderError": "Could not create new folder",
"createProjectError": "Could not create new project",
"createDataLinkError": "Could not create new Data Link",
"createDatalinkError": "Could not create new Datalink",
"createSecretError": "Could not create new secret",
"renameFolderError": "Could not rename folder",
"renameProjectError": "Could not rename project",
@ -15,7 +15,7 @@
"deleteAssetError": "Could not delete '$0'",
"restoreAssetError": "Could not restore '$0'",
"localBackendDataLinkError": "Cannot create Data Links on the local drive",
"localBackendDatalinkError": "Cannot create Datalinks on the local drive",
"localBackendSecretError": "Cannot create secrets on the local drive",
"offlineUploadFilesError": "Cannot upload files when offline",
@ -30,10 +30,10 @@
"editDescriptionError": "Could not edit description",
"canOnlyDownloadFilesError": "You currently can only download files.",
"noProjectSelectedError": "First select a project to download.",
"downloadInvalidTypeError": "You can only download files, projects, and Data Links",
"downloadInvalidTypeError": "You can only download files, projects, and Datalinks",
"downloadProjectError": "Could not download project '$0'",
"downloadFileError": "Could not download file '$0'",
"downloadDataLinkError": "Could not download Data Link '$0'",
"downloadDatalinkError": "Could not download Datalink '$0'",
"downloadSelectedFilesError": "Could not download selected files",
"openEditorError": "Could not open editor",
"setPermissionsError": "Could not set permissions",
@ -109,9 +109,9 @@
"uploadFileWithNameBackendError": "Could not upload file '$0'.",
"getFileDetailsBackendError": "Could not get details of project '$0'.",
"createSecretBackendError": "Could not create secret with name '$0'.",
"createConnectorBackendError": "Could not create Data Link with name '$0'.",
"getConnectorBackendError": "Could not get Data Link '$0'.",
"deleteConnectorBackendError": "Could not delete Data Link '$0'.",
"createDatalinkBackendError": "Could not create Datalink with name '$0'.",
"getDatalinkBackendError": "Could not get Datalink '$0'.",
"deleteDatalinkBackendError": "Could not delete Datalink '$0'.",
"getSecretBackendError": "Could not get secret '$0'.",
"updateSecretBackendError": "Could not update secret '$0'.",
"listSecretsBackendError": "Could not list secrets.",
@ -132,7 +132,7 @@
"directoryAssetType": "folder",
"projectAssetType": "project",
"fileAssetType": "file",
"connectorAssetType": "Data Link",
"datalinkAssetType": "Datalink",
"secretAssetType": "secret",
"specialLoadingAssetType": "special loading asset",
"specialEmptyAssetType": "special empty asset",
@ -187,8 +187,8 @@
"settingsFor": "Settings for ",
"inviteMembers": "Invite Members",
"versions": "Versions",
"dataLink": "Data Link",
"createDataLink": "Create Data Link",
"datalink": "Datalink",
"createDatalink": "Create Datalink",
"resetAll": "Reset All",
"openHelpChat": "Open Help Chat",
@ -242,7 +242,7 @@
"newProject": "New Project",
"uploadFiles": "Import",
"downloadFiles": "Export",
"newDataLink": "New Data Link",
"newDatalink": "New Datalink",
"newSecret": "New Secret",
"newLabel": "New Label",
@ -326,7 +326,7 @@
"clickForNewQuestion": "New question? Click to start a new thread!",
"upgradeToProNag": "Click here to upgrade to Enso Pro and get access to high-priority, live support!",
"projectNameCannotBeEmpty": "Project name cannot be empty.",
"remoteBackendSearchPlaceholder": "Type to search for projects, Data Links, users, and more.",
"remoteBackendSearchPlaceholder": "Type to search for projects, Datalinks, users, and more.",
"localBackendSearchPlaceholder": "Type to search for projects.",
"canOnlyEmptyTrashWhenInTrash": "Can only empty trash when in Trash",
"upgradeTo": "Upgrade to $0",
@ -361,7 +361,7 @@
"secretValueHidden": "●●●●●●●●",
"secretNamePlaceholder": "Enter the name of the secret",
"secretValuePlaceholder": "Enter the value of the secret",
"dataLinkNamePlaceholder": "Enter the name of the Data Link",
"datalinkNamePlaceholder": "Enter the name of the Datalink",
"labelNamePlaceholder": "Enter the name of the label",
"labelSearchPlaceholder": "Type labels to search",
"inviteUserPlaceholder": "Type usernames or emails to search or invite",
@ -421,15 +421,15 @@
"soloPlanName": "Solo",
"soloPlanSubtitle": "For individuals",
"soloPlanPricing": "$60 per user / month",
"soloPlanFeatures": "10GB Cloud Storage; 1 User; Data Links; Version Control for files and workflows; Enso Copilot",
"soloPlanFeatures": "10GB Cloud Storage; 1 User; Datalinks; Version Control for files and workflows; Enso Copilot",
"teamPlanName": "Team",
"teamPlanSubtitle": "For small teams",
"teamPlanPricing": "$150 per user / month",
"teamPlanFeatures": "100GB Cloud Storage; Up to 10 users sharing; Data Links; Version Control for files and workflows; Enso Copilot; Multiple Lifecycle Environments",
"teamPlanFeatures": "100GB Cloud Storage; Up to 10 users sharing; Datalinks; Version Control for files and workflows; Enso Copilot; Multiple Lifecycle Environments",
"enterprisePlanName": "Organization",
"enterprisePlanSubtitle": "For large organizations",
"enterprisePlanPricing": "Contact Sales",
"enterprisePlanFeatures": "1000+GB Cloud Storage; Unlimited users sharing; Data Links; Version Control for files and workflows; Enso Copilot; Multiple Lifecycle Environments; Data access and modification logs; Priority Support; Fine-grained files and workflows permissions; Federated Log On",
"enterprisePlanFeatures": "1000+GB Cloud Storage; Unlimited users sharing; Datalinks; Version Control for files and workflows; Enso Copilot; Multiple Lifecycle Environments; Data access and modification logs; Priority Support; Fine-grained files and workflows permissions; Federated Log On",
"subscribe": "Subscribe",
"learnMore": "Learn More",
"returnToDashboard": "Return to Dashboard",
@ -482,7 +482,7 @@
"uploadFilesShortcut": "Upload Files",
"newProjectShortcut": "New Project",
"newFolderShortcut": "New Folder",
"newDataLinkShortcut": "New Data Link",
"newDatalinkShortcut": "New Datalink",
"newSecretShortcut": "New Secret",
"useInNewProjectShortcut": "Use In New Project",
"closeModalShortcut": "Close",

View File

@ -59,7 +59,7 @@ interface PlaceholderOverrides {
readonly enterTheNewKeyboardShortcutFor: [actionName: string]
readonly downloadProjectError: [projectName: string]
readonly downloadFileError: [fileName: string]
readonly downloadDataLinkError: [dataLinkName: string]
readonly downloadDatalinkError: [datalinkName: string]
readonly deleteUserGroupError: [userGroupName: string]
readonly removeUserFromUserGroupError: [userName: string, userGroupName: string]
readonly deleteUserError: [userName: string]
@ -84,9 +84,9 @@ interface PlaceholderOverrides {
readonly checkResourcesBackendError: [string]
readonly uploadFileWithNameBackendError: [string]
readonly getFileDetailsBackendError: [string]
readonly createConnectorBackendError: [string]
readonly getConnectorBackendError: [string]
readonly deleteConnectorBackendError: [string]
readonly createDatalinkBackendError: [string]
readonly getDatalinkBackendError: [string]
readonly deleteDatalinkBackendError: [string]
readonly createSecretBackendError: [string]
readonly getSecretBackendError: [string]
readonly updateSecretBackendError: [string]

View File

@ -9,7 +9,7 @@ import * as appConfig from 'enso-common/src/appConfig'
appConfig.loadTestEnvironmentVariables()
// @ts-expect-error This is required, otherwise importing node modules is broken.
// This is required for `dataLinkSchema.test.ts`.
// This is required for `datalinkSchema.test.ts`.
process.env.NODE_ENV = 'development'
const VITE_CONFIG = (await import('./vite.config')).default