2024-01-31 14:35:41 +03:00
|
|
|
/** @file The mock API. */
|
|
|
|
import * as test from '@playwright/test'
|
|
|
|
|
2024-02-07 14:26:59 +03:00
|
|
|
import * as backend from '#/services/Backend'
|
|
|
|
import type * as remoteBackend from '#/services/RemoteBackend'
|
|
|
|
import * as remoteBackendPaths from '#/services/remoteBackendPaths'
|
|
|
|
|
|
|
|
import * as dateTime from '#/utilities/dateTime'
|
2024-01-31 14:35:41 +03:00
|
|
|
import * as object from '#/utilities/object'
|
|
|
|
import * as permissions from '#/utilities/permissions'
|
2024-02-07 14:26:59 +03:00
|
|
|
import * as uniqueString from '#/utilities/uniqueString'
|
2024-01-31 14:35:41 +03:00
|
|
|
|
|
|
|
// =================
|
|
|
|
// === Constants ===
|
|
|
|
// =================
|
|
|
|
|
|
|
|
/** The HTTP status code representing a response with an empty body. */
|
|
|
|
const HTTP_STATUS_NO_CONTENT = 204
|
|
|
|
/** The HTTP status code representing a bad request. */
|
|
|
|
const HTTP_STATUS_BAD_REQUEST = 400
|
|
|
|
/** The HTTP status code representing a URL that does not exist. */
|
|
|
|
const HTTP_STATUS_NOT_FOUND = 404
|
|
|
|
/** An asset ID that is a path glob. */
|
|
|
|
const GLOB_ASSET_ID: backend.AssetId = backend.DirectoryId('*')
|
|
|
|
/** A directory ID that is a path glob. */
|
|
|
|
const GLOB_DIRECTORY_ID = backend.DirectoryId('*')
|
|
|
|
/** A project ID that is a path glob. */
|
|
|
|
const GLOB_PROJECT_ID = backend.ProjectId('*')
|
|
|
|
/** A tag ID that is a path glob. */
|
|
|
|
const GLOB_TAG_ID = backend.TagId('*')
|
|
|
|
/* eslint-enable no-restricted-syntax */
|
2024-03-08 06:14:26 +03:00
|
|
|
const BASE_URL = 'https://mock/'
|
2024-01-31 14:35:41 +03:00
|
|
|
|
|
|
|
// ===============
|
|
|
|
// === mockApi ===
|
|
|
|
// ===============
|
|
|
|
|
|
|
|
/** Parameters for {@link mockApi}. */
|
|
|
|
interface MockParams {
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly page: test.Page
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Add route handlers for the mock API to a page. */
|
|
|
|
// This syntax is required for Playwright to work properly.
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
export async function mockApi({ page }: MockParams) {
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
const defaultEmail = 'email@example.com' as backend.EmailAddress
|
|
|
|
const defaultUsername = 'user name'
|
2024-02-13 12:21:40 +03:00
|
|
|
const defaultOrganizationId = backend.OrganizationId('organization-placeholder id')
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
const defaultUserId = backend.UserId('user-placeholder id')
|
2024-01-31 14:35:41 +03:00
|
|
|
const defaultDirectoryId = backend.DirectoryId('directory-placeholder id')
|
2024-02-13 12:21:40 +03:00
|
|
|
const defaultUser: backend.User = {
|
2024-01-31 14:35:41 +03:00
|
|
|
email: defaultEmail,
|
|
|
|
name: defaultUsername,
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
organizationId: defaultOrganizationId,
|
|
|
|
userId: defaultUserId,
|
2024-01-31 14:35:41 +03:00
|
|
|
isEnabled: true,
|
|
|
|
rootDirectoryId: defaultDirectoryId,
|
2024-05-09 15:04:35 +03:00
|
|
|
userGroups: null,
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
2024-02-13 12:21:40 +03:00
|
|
|
let currentUser: backend.User | null = defaultUser
|
2024-02-26 18:50:00 +03:00
|
|
|
let currentOrganization: backend.OrganizationInfo | null = null
|
2024-01-31 14:35:41 +03:00
|
|
|
const assetMap = new Map<backend.AssetId, backend.AnyAsset>()
|
|
|
|
const deletedAssets = new Set<backend.AssetId>()
|
|
|
|
const assets: backend.AnyAsset[] = []
|
|
|
|
const labels: backend.Label[] = []
|
|
|
|
const labelsByValue = new Map<backend.LabelName, backend.Label>()
|
|
|
|
const labelMap = new Map<backend.TagId, backend.Label>()
|
|
|
|
|
|
|
|
const addAsset = <T extends backend.AnyAsset>(asset: T) => {
|
|
|
|
assets.push(asset)
|
|
|
|
assetMap.set(asset.id, asset)
|
|
|
|
return asset
|
|
|
|
}
|
|
|
|
|
|
|
|
const deleteAsset = (assetId: backend.AssetId) => {
|
|
|
|
deletedAssets.add(assetId)
|
|
|
|
}
|
|
|
|
|
|
|
|
const undeleteAsset = (assetId: backend.AssetId) => {
|
|
|
|
deletedAssets.delete(assetId)
|
|
|
|
}
|
|
|
|
|
|
|
|
const createDirectory = (
|
|
|
|
title: string,
|
|
|
|
rest: Partial<backend.DirectoryAsset> = {}
|
|
|
|
): backend.DirectoryAsset =>
|
|
|
|
object.merge(
|
|
|
|
{
|
|
|
|
type: backend.AssetType.directory,
|
|
|
|
id: backend.DirectoryId('directory-' + uniqueString.uniqueString()),
|
|
|
|
projectState: null,
|
|
|
|
title,
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
description: null,
|
|
|
|
labels: [],
|
|
|
|
parentId: defaultDirectoryId,
|
|
|
|
permissions: [],
|
|
|
|
},
|
|
|
|
rest
|
|
|
|
)
|
|
|
|
|
|
|
|
const createProject = (
|
|
|
|
title: string,
|
|
|
|
rest: Partial<backend.ProjectAsset> = {}
|
|
|
|
): backend.ProjectAsset =>
|
|
|
|
object.merge(
|
|
|
|
{
|
|
|
|
type: backend.AssetType.project,
|
|
|
|
id: backend.ProjectId('project-' + uniqueString.uniqueString()),
|
|
|
|
projectState: {
|
|
|
|
type: backend.ProjectState.opened,
|
2024-04-11 23:02:29 +03:00
|
|
|
volumeId: '',
|
2024-01-31 14:35:41 +03:00
|
|
|
},
|
|
|
|
title,
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
description: null,
|
|
|
|
labels: [],
|
|
|
|
parentId: defaultDirectoryId,
|
|
|
|
permissions: [],
|
|
|
|
},
|
|
|
|
rest
|
|
|
|
)
|
|
|
|
|
|
|
|
const createFile = (title: string, rest: Partial<backend.FileAsset> = {}): backend.FileAsset =>
|
|
|
|
object.merge(
|
|
|
|
{
|
|
|
|
type: backend.AssetType.file,
|
|
|
|
id: backend.FileId('file-' + uniqueString.uniqueString()),
|
|
|
|
projectState: null,
|
|
|
|
title,
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
description: null,
|
|
|
|
labels: [],
|
|
|
|
parentId: defaultDirectoryId,
|
|
|
|
permissions: [],
|
|
|
|
},
|
|
|
|
rest
|
|
|
|
)
|
|
|
|
|
|
|
|
const createSecret = (
|
|
|
|
title: string,
|
|
|
|
rest: Partial<backend.SecretAsset> = {}
|
|
|
|
): backend.SecretAsset =>
|
|
|
|
object.merge(
|
|
|
|
{
|
|
|
|
type: backend.AssetType.secret,
|
|
|
|
id: backend.SecretId('secret-' + uniqueString.uniqueString()),
|
|
|
|
projectState: null,
|
|
|
|
title,
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
description: null,
|
|
|
|
labels: [],
|
|
|
|
parentId: defaultDirectoryId,
|
|
|
|
permissions: [],
|
|
|
|
},
|
|
|
|
rest
|
|
|
|
)
|
|
|
|
|
|
|
|
const createLabel = (value: string, color: backend.LChColor): backend.Label => ({
|
|
|
|
id: backend.TagId('tag-' + uniqueString.uniqueString()),
|
|
|
|
value: backend.LabelName(value),
|
|
|
|
color,
|
|
|
|
})
|
|
|
|
|
|
|
|
const addDirectory = (title: string, rest?: Partial<backend.DirectoryAsset>) => {
|
|
|
|
return addAsset(createDirectory(title, rest))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addProject = (title: string, rest?: Partial<backend.ProjectAsset>) => {
|
|
|
|
return addAsset(createProject(title, rest))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addFile = (title: string, rest?: Partial<backend.FileAsset>) => {
|
|
|
|
return addAsset(createFile(title, rest))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addSecret = (title: string, rest?: Partial<backend.SecretAsset>) => {
|
|
|
|
return addAsset(createSecret(title, rest))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addLabel = (value: string, color: backend.LChColor) => {
|
|
|
|
const label = createLabel(value, color)
|
|
|
|
labels.push(label)
|
|
|
|
labelsByValue.set(label.value, label)
|
|
|
|
labelMap.set(label.id, label)
|
|
|
|
return label
|
|
|
|
}
|
|
|
|
|
|
|
|
const setLabels = (id: backend.AssetId, newLabels: backend.LabelName[]) => {
|
|
|
|
const ids = new Set<backend.AssetId>([id])
|
|
|
|
for (const [innerId, asset] of assetMap) {
|
|
|
|
if (ids.has(asset.parentId)) {
|
|
|
|
ids.add(innerId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const innerId of ids) {
|
|
|
|
const asset = assetMap.get(innerId)
|
|
|
|
if (asset != null) {
|
2024-02-07 14:26:59 +03:00
|
|
|
object.unsafeMutable(asset).labels = newLabels
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await test.test.step('Mock API', async () => {
|
Refactor CSS; address some design issues (#9260)
- Implement https://github.com/enso-org/cloud-v2/issues/924
- Refactor all numbers out to CSS variables
- Implement some issues raised in the design meeting
- The columns selector now only contains *hidden* columns, rather than all of them.
- Unified opacity for active (100%), selectable and hovered (75%), selectable (50%) and disabled (30%)
- Easily configurable if we want to change it in the future, so the specific values don't matter too much for now.
- Always show asset right panel if it is enabled - display placeholder text if <1 or >1 asset is selected
- Hide docs icon that was in the top right assets menubar (next to the gear icon for asset settings) (as backend functionality has yet to be implemented)
- Clicking a user in the "Shared with" column now adds them to the search as `owner:<username>`
- Add a gap between adjacent rows. This makes each row more visually distinct when many rows are selected
- Center the left column (the first column) of the context menu below the mouse, rather than centering the entire context menu.
- Fix regressions caused by CSS refactor
- Make keyboard selection indicator for asset rows rounded again
- Other misc. fixes and improvements
- Slightly modified styling of chat reaction bar
- Hide the row containing the "New Project" button in the cloud drive, when not in the "Home" drive tab
- Animate rotation of column sort arrow when clicking on a column to change the sort order
- Consistent duration of arrow rotation animation for folder arrows, column sort arrows, chat thread list arrows
- Consistent icon for sort arrow for folders and the chat thread list
- Minor adjustment of styles for optional properties in the Data Link input
Not included in this PR:
- Custom (HTML) scrollbars for consistency across all browsers and all OSes (except perhaps touchscreens)
- Potentially time-consuming to look for a library (and not quite trivial to implement ourselves)
- Columns sliding left as they expand and right as they collapse
- Also non-trivial, especially when taking into account horizontal scrolling.
- Fixing styles to closer resemble Figma design
- As (kinda) mentioned in the meeting - ideally it should be pixel perfect, *but* value consistency with other spacings, opacities etc. over being 100% pixel-perfect
- However, it has *partly* been done - mostly for the home page. It's entirely possible that changes made afterwards broke the spacing again though.
# Important Notes
None
2024-03-13 13:32:05 +03:00
|
|
|
await page.route('https://cdn.enso.org/**', async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
|
|
|
|
2024-01-31 14:35:41 +03:00
|
|
|
await page.route('https://www.google-analytics.com/**', async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
|
|
|
|
|
|
|
await page.route('https://www.googletagmanager.com/gtag/js*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
contentType: 'text/javascript',
|
|
|
|
body: 'export {};',
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
const isOnline = await page.evaluate(() => navigator.onLine)
|
|
|
|
|
|
|
|
if (!isOnline) {
|
|
|
|
await page.route('https://fonts.googleapis.com/*', async route => {
|
|
|
|
await route.abort()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
await page.route(BASE_URL + '**', (_route, request) => {
|
|
|
|
throw new Error(`Missing route handler for '${request.url().replace(BASE_URL, '')}'.`)
|
|
|
|
})
|
|
|
|
|
|
|
|
// === Endpoints returning arrays ===
|
|
|
|
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.LIST_DIRECTORY_PATH + '*',
|
|
|
|
async (route, request) => {
|
|
|
|
/** The type for the search query for this endpoint. */
|
|
|
|
interface Query {
|
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly parent_id?: string
|
|
|
|
readonly filter_by?: backend.FilterBy
|
|
|
|
readonly labels?: backend.LabelName[]
|
|
|
|
readonly recent_projects?: boolean
|
2024-01-31 14:35:41 +03:00
|
|
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
|
|
}
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
const body = Object.fromEntries(
|
|
|
|
new URL(request.url()).searchParams.entries()
|
|
|
|
) as unknown as Query
|
|
|
|
const parentId = body.parent_id ?? defaultDirectoryId
|
|
|
|
let filteredAssets = assets.filter(asset => asset.parentId === parentId)
|
|
|
|
// This lint rule is broken; there is clearly a case for `undefined` below.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
|
|
switch (body.filter_by) {
|
|
|
|
case backend.FilterBy.active: {
|
|
|
|
filteredAssets = filteredAssets.filter(asset => !deletedAssets.has(asset.id))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case backend.FilterBy.trashed: {
|
|
|
|
filteredAssets = filteredAssets.filter(asset => deletedAssets.has(asset.id))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case backend.FilterBy.recent: {
|
|
|
|
filteredAssets = assets
|
|
|
|
.filter(asset => !deletedAssets.has(asset.id))
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
|
|
.slice(0, 10)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case backend.FilterBy.all:
|
|
|
|
case null: {
|
|
|
|
// do nothing
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
case undefined: {
|
|
|
|
// do nothing
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
filteredAssets.sort(
|
|
|
|
(a, b) => backend.ASSET_TYPE_ORDER[a.type] - backend.ASSET_TYPE_ORDER[b.type]
|
|
|
|
)
|
|
|
|
await route.fulfill({
|
|
|
|
json: {
|
|
|
|
assets: filteredAssets,
|
|
|
|
} satisfies remoteBackend.ListDirectoryResponseBody,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.LIST_FILES_PATH + '*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: { files: [] } satisfies remoteBackend.ListFilesResponseBody,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.LIST_PROJECTS_PATH + '*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: { projects: [] } satisfies remoteBackend.ListProjectsResponseBody,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.LIST_SECRETS_PATH + '*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: { secrets: [] } satisfies remoteBackend.ListSecretsResponseBody,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.LIST_TAGS_PATH + '*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: { tags: labels } satisfies remoteBackend.ListTagsResponseBody,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.LIST_USERS_PATH + '*', async route => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: { users: [] } satisfies remoteBackend.ListUsersResponseBody,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.LIST_VERSIONS_PATH + '*',
|
|
|
|
async (route, request) => {
|
|
|
|
await route.fulfill({
|
|
|
|
json: {
|
|
|
|
versions: [
|
|
|
|
{
|
|
|
|
ami: null,
|
|
|
|
created: dateTime.toRfc3339(new Date()),
|
|
|
|
number: {
|
|
|
|
lifecycle:
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
'Development' satisfies `${backend.VersionLifecycle.development}` as backend.VersionLifecycle.development,
|
|
|
|
value: '2023.2.1-dev',
|
|
|
|
},
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention, no-restricted-syntax
|
|
|
|
version_type: (new URL(request.url()).searchParams.get('version_type') ??
|
|
|
|
'') as backend.VersionType,
|
|
|
|
} satisfies backend.Version,
|
|
|
|
],
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// === Unimplemented endpoints ===
|
|
|
|
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.getProjectDetailsPath(GLOB_PROJECT_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
const projectId = request.url().match(/[/]projects[/](.+?)[/]copy/)?.[1] ?? ''
|
|
|
|
await route.fulfill({
|
|
|
|
json: {
|
|
|
|
organizationId: defaultOrganizationId,
|
|
|
|
projectId: backend.ProjectId(projectId),
|
|
|
|
name: 'example project name',
|
|
|
|
state: {
|
|
|
|
type: backend.ProjectState.opened,
|
2024-04-11 23:02:29 +03:00
|
|
|
volumeId: '',
|
|
|
|
openedBy: defaultEmail,
|
2024-01-31 14:35:41 +03:00
|
|
|
},
|
|
|
|
packageName: 'Project_root',
|
2024-04-11 23:02:29 +03:00
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
2024-01-31 14:35:41 +03:00
|
|
|
ide_version: null,
|
2024-04-11 23:02:29 +03:00
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
2024-01-31 14:35:41 +03:00
|
|
|
engine_version: {
|
|
|
|
value: '2023.2.1-nightly.2023.9.29',
|
|
|
|
lifecycle: backend.VersionLifecycle.development,
|
|
|
|
},
|
|
|
|
address: backend.Address('ws://example.com/'),
|
|
|
|
} satisfies backend.ProjectRaw,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// === Endpoints returning `void` ===
|
|
|
|
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.copyAssetPath(GLOB_ASSET_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
/** The type for the JSON request payload for this endpoint. */
|
|
|
|
interface Body {
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly parentDirectoryId: backend.DirectoryId
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
const assetId = request.url().match(/[/]assets[/](.+?)[/]copy/)?.[1]
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
const asset = assetId != null ? assetMap.get(assetId as backend.AssetId) : null
|
|
|
|
if (asset == null) {
|
|
|
|
if (assetId == null) {
|
|
|
|
await route.fulfill({
|
|
|
|
status: HTTP_STATUS_BAD_REQUEST,
|
|
|
|
json: { error: 'Invalid Asset ID' },
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
await route.fulfill({
|
|
|
|
status: HTTP_STATUS_NOT_FOUND,
|
|
|
|
json: { error: 'Asset does not exist' },
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: Body = await request.postDataJSON()
|
|
|
|
const parentId = body.parentDirectoryId
|
|
|
|
// Can be any asset ID.
|
|
|
|
const id = backend.DirectoryId(uniqueString.uniqueString())
|
|
|
|
const json: backend.CopyAssetResponse = {
|
|
|
|
asset: {
|
|
|
|
id,
|
|
|
|
parentId,
|
|
|
|
title: asset.title + ' (copy)',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
const newAsset = { ...asset }
|
|
|
|
newAsset.id = id
|
|
|
|
newAsset.parentId = parentId
|
|
|
|
newAsset.title += ' (copy)'
|
|
|
|
addAsset(newAsset)
|
|
|
|
await route.fulfill({ json })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.INVITE_USER_PATH + '*', async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.CREATE_PERMISSION_PATH + '*', async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.deleteAssetPath(GLOB_ASSET_ID), async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.closeProjectPath(GLOB_PROJECT_ID),
|
|
|
|
async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.openProjectPath(GLOB_PROJECT_ID),
|
|
|
|
async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.deleteTagPath(GLOB_TAG_ID), async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
2024-05-27 20:32:42 +03:00
|
|
|
await page.route(BASE_URL + remoteBackendPaths.POST_LOG_EVENT_PATH, async route => {
|
|
|
|
await route.fulfill()
|
|
|
|
})
|
2024-01-31 14:35:41 +03:00
|
|
|
|
|
|
|
// === Other endpoints ===
|
|
|
|
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.updateAssetPath(GLOB_ASSET_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'PATCH') {
|
|
|
|
const assetId = request.url().match(/[/]assets[/]([^?]+)/)?.[1] ?? ''
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.UpdateAssetRequestBody = request.postDataJSON()
|
|
|
|
// This could be an id for an arbitrary asset, but pretend it's a
|
|
|
|
// `DirectoryId` to make TypeScript happy.
|
|
|
|
const asset = assetMap.get(backend.DirectoryId(assetId))
|
|
|
|
if (asset != null) {
|
|
|
|
if (body.description != null) {
|
2024-02-07 14:26:59 +03:00
|
|
|
object.unsafeMutable(asset).description = body.description
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.associateTagPath(GLOB_ASSET_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'PATCH') {
|
|
|
|
const assetId = request.url().match(/[/]assets[/]([^/?]+)/)?.[1] ?? ''
|
|
|
|
/** The type for the JSON request payload for this endpoint. */
|
|
|
|
interface Body {
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly labels: backend.LabelName[]
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
/** The type for the JSON response payload for this endpoint. */
|
|
|
|
interface Response {
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly tags: backend.Label[]
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: Body = await request.postDataJSON()
|
|
|
|
// This could be an id for an arbitrary asset, but pretend it's a
|
|
|
|
// `DirectoryId` to make TypeScript happy.
|
|
|
|
setLabels(backend.DirectoryId(assetId), body.labels)
|
|
|
|
const json: Response = {
|
|
|
|
tags: body.labels.flatMap(value => {
|
|
|
|
const label = labelsByValue.get(value)
|
|
|
|
return label != null ? [label] : []
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
await route.fulfill({ json })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.updateDirectoryPath(GLOB_DIRECTORY_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'PUT') {
|
|
|
|
const directoryId = request.url().match(/[/]directories[/]([^?]+)/)?.[1] ?? ''
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.UpdateDirectoryRequestBody = request.postDataJSON()
|
|
|
|
const asset = assetMap.get(backend.DirectoryId(directoryId))
|
|
|
|
if (asset == null) {
|
|
|
|
await route.abort()
|
|
|
|
} else {
|
2024-02-07 14:26:59 +03:00
|
|
|
object.unsafeMutable(asset).title = body.title
|
2024-01-31 14:35:41 +03:00
|
|
|
await route.fulfill({
|
|
|
|
json: {
|
|
|
|
id: backend.DirectoryId(directoryId),
|
|
|
|
parentId: asset.parentId,
|
|
|
|
title: body.title,
|
|
|
|
} satisfies backend.UpdatedDirectory,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.deleteAssetPath(GLOB_ASSET_ID),
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'DELETE') {
|
|
|
|
const assetId = request.url().match(/[/]assets[/]([^?]+)/)?.[1] ?? ''
|
|
|
|
// This could be an id for an arbitrary asset, but pretend it's a
|
|
|
|
// `DirectoryId` to make TypeScript happy.
|
|
|
|
deleteAsset(backend.DirectoryId(assetId))
|
|
|
|
await route.fulfill({ status: HTTP_STATUS_NO_CONTENT })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.UNDO_DELETE_ASSET_PATH,
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'PATCH') {
|
|
|
|
/** The type for the JSON request payload for this endpoint. */
|
|
|
|
interface Body {
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly assetId: backend.AssetId
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: Body = await request.postDataJSON()
|
|
|
|
undeleteAsset(body.assetId)
|
|
|
|
await route.fulfill({ status: HTTP_STATUS_NO_CONTENT })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.CREATE_USER_PATH + '*',
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'POST') {
|
|
|
|
// The type of the body sent by this app is statically known.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.CreateUserRequestBody = await request.postDataJSON()
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
const organizationId = body.organizationId ?? defaultUser.organizationId
|
|
|
|
const rootDirectoryId = backend.DirectoryId(
|
|
|
|
organizationId.replace(/^organization-/, 'directory-')
|
|
|
|
)
|
2024-01-31 14:35:41 +03:00
|
|
|
currentUser = {
|
|
|
|
email: body.userEmail,
|
|
|
|
name: body.userName,
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
organizationId,
|
|
|
|
userId: backend.UserId(`user-${uniqueString.uniqueString()}`),
|
2024-01-31 14:35:41 +03:00
|
|
|
isEnabled: false,
|
|
|
|
rootDirectoryId,
|
2024-05-09 15:04:35 +03:00
|
|
|
userGroups: null,
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
await route.fulfill({ json: currentUser })
|
|
|
|
} else if (request.method() === 'GET') {
|
|
|
|
if (currentUser != null) {
|
|
|
|
await route.fulfill({ json: [] })
|
|
|
|
} else {
|
|
|
|
await route.fulfill({ status: HTTP_STATUS_BAD_REQUEST })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.USERS_ME_PATH + '*', async route => {
|
2024-02-26 18:50:00 +03:00
|
|
|
await route.fulfill({ json: currentUser })
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.GET_ORGANIZATION_PATH + '*', async route => {
|
2024-01-31 14:35:41 +03:00
|
|
|
await route.fulfill({
|
2024-02-26 18:50:00 +03:00
|
|
|
json: currentOrganization,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
|
|
status: currentOrganization == null ? 404 : 200,
|
2024-01-31 14:35:41 +03:00
|
|
|
})
|
|
|
|
})
|
|
|
|
await page.route(BASE_URL + remoteBackendPaths.CREATE_TAG_PATH + '*', async route => {
|
|
|
|
if (route.request().method() === 'POST') {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.CreateTagRequestBody = route.request().postDataJSON()
|
|
|
|
const json: backend.Label = {
|
|
|
|
id: backend.TagId(`tag-${uniqueString.uniqueString()}`),
|
|
|
|
value: backend.LabelName(body.value),
|
|
|
|
color: body.color,
|
|
|
|
}
|
|
|
|
await route.fulfill({ json })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.CREATE_PROJECT_PATH + '*',
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'POST') {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.CreateProjectRequestBody = request.postDataJSON()
|
|
|
|
const title = body.projectName
|
|
|
|
const id = backend.ProjectId(`project-${uniqueString.uniqueString()}`)
|
|
|
|
const parentId =
|
|
|
|
body.parentDirectoryId ??
|
|
|
|
backend.DirectoryId(`directory-${uniqueString.uniqueString()}`)
|
|
|
|
const json: backend.CreatedProject = {
|
|
|
|
name: title,
|
|
|
|
organizationId: defaultOrganizationId,
|
|
|
|
packageName: 'Project_root',
|
|
|
|
projectId: id,
|
2024-04-11 23:02:29 +03:00
|
|
|
state: { type: backend.ProjectState.opened, volumeId: '' },
|
2024-01-31 14:35:41 +03:00
|
|
|
}
|
|
|
|
addProject(title, {
|
|
|
|
description: null,
|
|
|
|
id,
|
|
|
|
labels: [],
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
parentId,
|
|
|
|
permissions: [
|
|
|
|
{
|
|
|
|
user: {
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
organizationId: defaultOrganizationId,
|
|
|
|
userId: defaultUserId,
|
|
|
|
name: defaultUsername,
|
|
|
|
email: defaultEmail,
|
2024-01-31 14:35:41 +03:00
|
|
|
},
|
|
|
|
permission: permissions.PermissionAction.own,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
projectState: json.state,
|
|
|
|
})
|
|
|
|
await route.fulfill({ json })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
await page.route(
|
|
|
|
BASE_URL + remoteBackendPaths.CREATE_DIRECTORY_PATH + '*',
|
|
|
|
async (route, request) => {
|
|
|
|
if (request.method() === 'POST') {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const body: backend.CreateDirectoryRequestBody = request.postDataJSON()
|
|
|
|
const title = body.title
|
|
|
|
const id = backend.DirectoryId(`directory-${uniqueString.uniqueString()}`)
|
|
|
|
const parentId =
|
|
|
|
body.parentId ?? backend.DirectoryId(`directory-${uniqueString.uniqueString()}`)
|
|
|
|
const json: backend.CreatedDirectory = { title, id, parentId }
|
|
|
|
addDirectory(title, {
|
|
|
|
description: null,
|
|
|
|
id,
|
|
|
|
labels: [],
|
|
|
|
modifiedAt: dateTime.toRfc3339(new Date()),
|
|
|
|
parentId,
|
|
|
|
permissions: [
|
|
|
|
{
|
|
|
|
user: {
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
organizationId: defaultOrganizationId,
|
|
|
|
userId: defaultUserId,
|
|
|
|
name: defaultUsername,
|
|
|
|
email: defaultEmail,
|
2024-01-31 14:35:41 +03:00
|
|
|
},
|
|
|
|
permission: permissions.PermissionAction.own,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
projectState: null,
|
|
|
|
})
|
|
|
|
await route.fulfill({ json })
|
|
|
|
} else {
|
|
|
|
await route.fallback()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return {
|
|
|
|
defaultEmail,
|
|
|
|
defaultName: defaultUsername,
|
|
|
|
defaultOrganizationId,
|
|
|
|
defaultUser,
|
impr(enso/cloud-v2#912): Add `organization_id` and `user_id` fields to `SimpleUser` (#9508)
- Updates the model types for the request/response bodies to match the backend.
- Renames `CreatePermissionRequestBody::userSubjects` to match `CreatePermissionRequestBody::actorsIds` on the backend
- Renames `UserInfo::organization_id` to camel case
- Adds `UserInfo::userId` field to match the backend
- Merges `SimpleUser` into `UserInfo`
Previously, `UserInfo`'s `OrganizationId` was serialized as `pk`. This
is not desired since `pk` is an implementation detail (relating to
DynamoDB). This commit renames the field to accurately reflect the type
of data it contains.
- Renames `User::id` to `User::organizationId`.
Previously, the user's organization ID was under the `id` field. As of
enso-cloud/cloud-v2#1098, this is no longer the case. The
`organizationId` field is no longer a user's primary identifier --
`userId` should be used for that purpose instead. So this field has been
renamed to `organizationId` to more clearly describe the purpose of the
field.
Affects the responses expected from the following endpoints:
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
- Adds `User::userId` field.
Previously, the user's organization ID was used to uniquely identify a
user. Now that multiple users can be invited to an organization, it is
no longer appropriate to use organization ID to uniquely refer to a
user. For this purpose, the backend has introduced the `userId` field.
Affects the responses expected from the following endpoints:
- `POST /users`
- `PUT /users/me/picture`
- `PUT /users/me`
- `GET /users/me`
- `PUT /users/{userId}/usergroups`
Removes the `user` param from `tryGetSingletonOwnerPermission`. This
param was previously required. It was required because a `userSubject`
was necessary to optimistically generate a `UserPermission`. With recent
refactors, a `userId` can be used in place of `userSubject` to generate
a `UserPermission`. The existing param `owner` provides the `userId`, so
the `user` param is redundant and can be removed.
- Removes `UserInfo` from the `FullUserSession`.
Previously, `UserInfo` in the `FullUserSession` was required to obtain a
`userSubject`. Now, `userSubject` has been deprecated in favour of
`userId`. `User` provides `userId`, and is present in the
`FullUserSession`. Thus, this commit removes `UserInfo` from the
`FullUserSession` since it is redundant.
- Renames `UserInfo` fields to `camelCase`
Previously, `UserInfo`'s fields were serialized as `snake_case`. This is
not desired since the convention for the frontend is to use `camelCase`
for field names where possible. This commit renames the fields to be
`camelCase`, now that the backend has been updated accordingly.
- Sorts by `userId` rather than `email`
- Compares by `userId` rather than `email`
- Extends `User` from `UserInfo`
After refactoring, `UserInfo` is now a subset of `User`. To remove
duplication, this commit modifies `User` to extend `UserInfo`.
2024-03-27 17:58:08 +03:00
|
|
|
defaultUserId,
|
2024-01-31 14:35:41 +03:00
|
|
|
rootDirectoryId: defaultDirectoryId,
|
|
|
|
/** Returns the current value of `currentUser`. This is a getter, so its return value
|
|
|
|
* SHOULD NOT be cached. */
|
|
|
|
get currentUser() {
|
|
|
|
return currentUser
|
|
|
|
},
|
2024-02-13 12:21:40 +03:00
|
|
|
setCurrentUser: (user: backend.User | null) => {
|
2024-01-31 14:35:41 +03:00
|
|
|
currentUser = user
|
|
|
|
},
|
2024-02-26 18:50:00 +03:00
|
|
|
/** Returns the current value of `currentUser`. This is a getter, so its return value
|
|
|
|
* SHOULD NOT be cached. */
|
|
|
|
get currentOrganization() {
|
|
|
|
return currentOrganization
|
|
|
|
},
|
|
|
|
setCurrentOrganization: (user: backend.OrganizationInfo | null) => {
|
|
|
|
currentOrganization = user
|
|
|
|
},
|
2024-01-31 14:35:41 +03:00
|
|
|
addAsset,
|
|
|
|
deleteAsset,
|
|
|
|
undeleteAsset,
|
|
|
|
createDirectory,
|
|
|
|
createProject,
|
|
|
|
createFile,
|
|
|
|
createSecret,
|
|
|
|
addDirectory,
|
|
|
|
addProject,
|
|
|
|
addFile,
|
|
|
|
addSecret,
|
|
|
|
createLabel,
|
|
|
|
addLabel,
|
|
|
|
setLabels,
|
|
|
|
}
|
|
|
|
}
|