Skip to content

Commit

Permalink
Second iteration of Dashboard Fixes (#11781)
Browse files Browse the repository at this point in the history
Fixes:

- Opening deleted folder
- Icons
- Diff view collapsed
- Password input for passwords in settings
- Save button appears only if form in settings is dirty
- Disable clear trash button if it's empty
- Disable D&D in the root folder
- Disable Create actions if user select a folder without sufficient permissions
- Many more
  • Loading branch information
MrFlashAccount authored Dec 9, 2024
1 parent dca68ac commit 3ad09a1
Show file tree
Hide file tree
Showing 90 changed files with 1,963 additions and 1,086 deletions.
14 changes: 14 additions & 0 deletions app/common/src/services/Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1787,3 +1787,17 @@ export default abstract class Backend {
/** Resolve the path of an asset relative to a project. */
abstract resolveProjectAssetPath(projectId: ProjectId, relativePath: string): Promise<string>
}

// ==============================
// ====== Custom Errors =========
// ==============================

/** Error thrown when a directory does not exist. */
export class DirectoryDoesNotExistError extends Error {
/**
* Create a new instance of the {@link DirectoryDoesNotExistError} class.
*/
constructor() {
super('Directory does not exist.')
}
}
20 changes: 14 additions & 6 deletions app/common/src/text/english.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
"emptyStringError": "This value must not be empty.",

"directoryAssetType": "folder",
"directoryDoesNotExistError": "Unable to find directory. Does it exist?",
"projectAssetType": "project",
"fileAssetType": "file",
"datalinkAssetType": "Datalink",
Expand Down Expand Up @@ -306,22 +307,23 @@
"andOtherProjects": "and $0 other projects",

"cloudCategory": "Cloud",
"myFilesCategory": "Me",
"myFilesCategory": "My Files",
"recentCategory": "Recent",
"trashCategory": "Trash",
"userCategory": "$0",
"teamCategory": "$0",
"localCategory": "Local",
"cloudCategoryButtonLabel": "Cloud",
"myFilesCategoryButtonLabel": "Me",
"myFilesCategoryButtonLabel": "My Files",
"recentCategoryButtonLabel": "Recent",
"trashCategoryButtonLabel": "Trash",
"userCategoryButtonLabel": "$0 (User)",
"teamCategoryButtonLabel": "$0 (Team)",
"localCategoryButtonLabel": "Local",
"cloudCategoryDropZoneLabel": "Move to your organization's home directory",
"cloudCategoryBadgeContent": "Beta",
"myFilesCategoryDropZoneLabel": "Move to your home directory",
"uploadToCloudUnavailableForFreePlan": "",
"myFilesCategoryDropZoneLabel": "Move to My Files",
"recentCategoryDropZoneLabel": "Move to Recent category",
"trashCategoryDropZoneLabel": "Move to Trash category",
"userCategoryDropZoneLabel": "Move to $0's home directory",
Expand Down Expand Up @@ -400,7 +402,7 @@
"deleteTheAssetTypeTitle": "delete the $0 '$1'",
"trashTheAssetTypeTitle": "move the $0 '$1' to Trash",
"notImplemetedYet": "Not implemented yet.",
"newLabelButtonLabel": "new label",
"newLabelButtonLabel": "New label",
"settingUsername": "Setting username...",
"loggingOut": "Logging out...",
"pleaseWait": "Please wait...",
Expand All @@ -415,6 +417,7 @@
"version": "Version",
"build": "Build",
"errorColon": "Error: ",
"developerInfo": "Dev mode info",
"electronVersion": "Electron",
"chromeVersion": "Chrome",
"userAgent": "User Agent",
Expand All @@ -423,7 +426,7 @@
"projectSessionX": "Session $0",
"onDateX": "on $0",
"xUsersAndGroupsSelected": "$0 users and groups selected",
"allTrashedItemsForever": "all trashed items forever",
"allTrashedItemsForever": "delete all trashed items forever",
"addShortcut": "Add shortcut",
"removeShortcut": "Remove shortcut",
"resetShortcut": "Reset shortcut",
Expand Down Expand Up @@ -482,7 +485,7 @@
"disableAnimations": "Disable animations",
"disableAnimationsDescription": "Disable all animations in the app.",
"removeTheLocalDirectoryXFromFavorites": "remove the local folder '$0' from your favorites",
"changeLocalRootDirectoryInSettings": "Change your root folder in Settings.",
"changeLocalRootDirectoryInSettings": "Change the root folder",
"localStorage": "Local Storage",
"addLocalDirectory": "Add Folder",
"browseForNewLocalRootDirectory": "Browse for new Root Folder",
Expand Down Expand Up @@ -821,6 +824,7 @@
"arbitraryFieldNotContainAny": "This field does not contain any of the fields",

"arbitraryErrorTitle": "An error occurred",
"somethingWentWrong": "Something went wrong",
"arbitraryErrorSubtitle": "Please try again or contact the administrators.",
"arbitraryFormErrorMessage": "Something went wrong while submitting the form. Please try again or contact the administrators.",

Expand Down Expand Up @@ -942,6 +946,10 @@
"shareFullFeatureDescription": "Share unlimited assets with other users and manage shared assets. Assign shared assets to user groups to manage their permissions.",
"shareFullPaywallMessage": "You can only share assets with a single user group. Upgrade to share assets with multiple user groups and users.",

"uploadToCloudFeatureLabel": "Upload to Cloud",
"uploadToCloudFeatureBulletPoints": "Upload assets to the Cloud;Manage Cloud assets;Run projects in the Cloud",
"uploadToCloudFeatureDescription": "Upload assets to the cloud and manage them in the cloud. Run projects in the cloud.",

"ensoDevtoolsButtonLabel": "Open Enso Devtools",
"ensoDevtoolsPopoverHeading": "Enso Devtools",
"ensoDevtoolsPlanSelectSubtitle": "User Plan",
Expand Down
16 changes: 16 additions & 0 deletions app/common/src/utilities/data/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export function unsafeKeys<T extends object>(object: T): readonly (keyof T)[] {
return Object.keys(object)
}

/** Return the values of an object. UNSAFE only when it is possible for an object to have extra keys. */
export function unsafeValues<const T extends object>(object: T): readonly T[keyof T][] {
return Object.values(object)
}

/**
* Return the entries of an object. UNSAFE only when it is possible for an object to have
* extra keys.
Expand All @@ -77,6 +82,17 @@ export function unsafeEntries<T extends object>(
return Object.entries(object)
}

/**
* Return an object from its entries. UNSAFE only when it is possible for an object to have
* extra keys.
*/
export function unsafeFromEntries<T extends object>(
entries: readonly { [K in keyof T]: readonly [K, T[K]] }[keyof T][],
): T {
// @ts-expect-error This is intentionally a wrapper function with a different type.
return Object.fromEntries(entries)
}

// =============================
// === unsafeRemoveUndefined ===
// =============================
Expand Down
14 changes: 14 additions & 0 deletions app/gui/integration-test/dashboard/actions/DrivePageActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,18 @@ export default class DrivePageActions extends PageActions {
await callback(locateContextMenus(page))
})
}

/** Close the "get started" modal. */
closeGetStartedModal() {
return this.step('Close "get started" modal', async (page) => {
await new StartModalActions(page).close()
})
}

/** Interact with the "start" modal. */
withStartModal(callback: baseActions.LocatorCallback) {
return this.step('Interact with start modal', async (page) => {
await callback(new StartModalActions(page).locateStartModal())
})
}
}
31 changes: 26 additions & 5 deletions app/gui/integration-test/dashboard/actions/StartModalActions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file Actions for the "home" page. */
import * as test from '@playwright/test'
import * as actions from '.'
import BaseActions from './BaseActions'
import DrivePageActions from './DrivePageActions'
import EditorPageActions from './EditorPageActions'

// =========================
Expand All @@ -11,10 +11,31 @@ import EditorPageActions from './EditorPageActions'
/** Actions for the "start" modal. */
export default class StartModalActions extends BaseActions {
/** Close this modal and go back to the Drive page. */
close() {
return this.step('Close "start" modal', (page) => page.getByLabel('Close').click()).into(
DrivePageActions,
)
async close() {
const isOnScreen = await this.isStartModalShown()

if (isOnScreen) {
return test.test.step('Close start modal', async () => {
await this.locateStartModal().getByTestId('close-button').click()
})
}
}

/** Locate the "start" modal. */
locateStartModal() {
return this.page.getByTestId('start-modal')
}

/**
* Check if the Asset Panel is shown.
*/
isStartModalShown() {
return this.locateStartModal()
.isHidden()
.then(
(result) => !result,
() => false,
)
}

/** Create a project from the template at the given index. */
Expand Down
Loading

0 comments on commit 3ad09a1

Please sign in to comment.