Files app: Convert volume_manager_impl to TS
Bug: b/289003444
Change-Id: Ia28db67e92442ef8f5bd84d41d54544595140ae3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4956754
Commit-Queue: Cassy Chun-Crogan <cassycc@google.com>
Reviewed-by: Luciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1215248}
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn
index 1b62989..761b744 100644
--- a/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -97,7 +97,6 @@
js_library("mock_volume_manager") {
visibility += related_apps
deps = [
- ":volume_manager_impl",
"//ash/webui/common/resources:assert",
"//ui/file_manager/file_manager/common/js:mock_entry",
"//ui/file_manager/file_manager/common/js:util",
@@ -159,23 +158,8 @@
]
}
-js_library("volume_manager_impl") {
- deps = [
- ":volume_manager_util",
- "//ash/webui/common/resources:assert",
- "//ash/webui/common/resources:cr_deprecated",
- "//ash/webui/common/resources:event_target",
- "//ui/file_manager/file_manager/common/js:async_util",
- "//ui/file_manager/file_manager/common/js:util",
- "//ui/file_manager/file_manager/common/js:volume_manager_types",
- "//ui/file_manager/file_manager/externs:volume_manager",
- "//ui/file_manager/file_manager/externs/ts:store",
- ]
-}
-
js_unittest("volume_manager_unittest") {
deps = [
- ":volume_manager_impl",
":volume_manager_util",
"//ash/webui/common/resources:load_time_data.m",
"//chrome/test/data/webui/chromeos:chai_assert",
diff --git a/ui/file_manager/file_manager/background/js/entry_location_impl.ts b/ui/file_manager/file_manager/background/js/entry_location_impl.ts
index 56de5dc..829485c5 100644
--- a/ui/file_manager/file_manager/background/js/entry_location_impl.ts
+++ b/ui/file_manager/file_manager/background/js/entry_location_impl.ts
@@ -22,7 +22,7 @@
hasFixedLabel: boolean;
constructor(
- public volumeInfo: VolumeInfo,
+ public volumeInfo: VolumeInfo|null,
public rootType: VolumeManagerCommon.RootType,
public isRootEntry: boolean, public isReadOnly: boolean) {
this.isSpecialSearchRoot =
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.ts
similarity index 69%
rename from ui/file_manager/file_manager/background/js/volume_manager_impl.js
rename to ui/file_manager/file_manager/background/js/volume_manager_impl.ts
index 62803148..46446fa 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.ts
@@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import {assert} from 'chrome://resources/ash/common/assert.js';
import {dispatchSimpleEvent} from 'chrome://resources/ash/common/cr_deprecated.js';
import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js';
+import {assert} from 'chrome://resources/js/assert.js';
import {promisify} from '../../common/js/api.js';
-import {isComputersRoot, isFakeEntry, isSameEntry, isSameFileSystem, isTeamDriveRoot} from '../../common/js/entry_utils.js';
+import {getRootType, isComputersRoot, isFakeEntry, isSameEntry, isSameFileSystem, isTeamDriveRoot} from '../../common/js/entry_utils.js';
import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
+import {EntryLocation} from '../../externs/entry_location.js';
+import {FilesAppDirEntry, FilesAppEntry} from '../../externs/files_app_entry_interfaces.js';
+import type {VolumeInfo} from '../../externs/volume_info.js';
import {VolumeManager} from '../../externs/volume_manager.js';
import {removeVolume} from '../../state/ducks/volumes.js';
import {getStore} from '../../state/store.js';
@@ -17,106 +20,95 @@
import {VolumeInfoListImpl} from './volume_info_list_impl.js';
import {volumeManagerUtil} from './volume_manager_util.js';
+type VolumeAlreadyMountedEvent = Event&{
+ volumeId: string,
+};
+
+type RequestSuccessCallback = (volumeInfo?: VolumeInfo) => void;
+type RequestErrorCallback = (error: VolumeManagerCommon.VolumeError) => void;
+interface Request {
+ successCallbacks: RequestSuccessCallback[];
+ errorCallbacks: RequestErrorCallback[];
+ timeout: number;
+}
+
/**
* VolumeManager is responsible for tracking list of mounted volumes.
- * @implements {VolumeManager}
*/
-export class VolumeManagerImpl extends EventTarget {
+export class VolumeManagerImpl extends EventTarget implements VolumeManager {
+ volumeInfoList = new VolumeInfoListImpl();
+
+ /**
+ * The list of archives requested to mount. We will show contents once
+ * archive is mounted, but only for mounts from within this filebrowser tab.
+ * TODO: Add interface to replace `any` below.
+ */
+ private requests_: Record<string, Request> = {};
+
+ // The status should be merged into VolumeManager.
+ // TODO(hidehiko): Remove them after the migration.
+ /**
+ * Connection state of the Drive.
+ */
+ private driveConnectionState_:
+ chrome.fileManagerPrivate.DriveConnectionState = {
+ type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE,
+ reason: chrome.fileManagerPrivate.DriveOfflineReason.NO_SERVICE,
+ };
+
+ /**
+ * Holds the resolver for the `waitForInitialization_` promise.
+ */
+ private finishInitialization_: (() => void)|null = null;
+
+ /**
+ * Promise used to wait for the initialize() method to finish.
+ */
+ private waitForInitialization_: Promise<void> =
+ new Promise(resolve => this.finishInitialization_ = resolve);
+
constructor() {
super();
- /** @override */
- this.volumeInfoList = new VolumeInfoListImpl();
-
- /**
- * The list of archives requested to mount. We will show contents once
- * archive is mounted, but only for mounts from within this filebrowser tab.
- * TODO: Add interface to replace `any` below.
- * @type {Record<string, any>}
- * @private
- */
- this.requests_ = {};
-
- // The status should be merged into VolumeManager.
- // TODO(hidehiko): Remove them after the migration.
- /**
- * Connection state of the Drive.
- * @type {chrome.fileManagerPrivate.DriveConnectionState}
- * @private
- */
- this.driveConnectionState_ = {
- type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE,
- reason: chrome.fileManagerPrivate.DriveOfflineReason.NO_SERVICE,
- };
-
chrome.fileManagerPrivate.onDriveConnectionStatusChanged.addListener(
this.onDriveConnectionStatusChanged_.bind(this));
this.onDriveConnectionStatusChanged_();
- /**
- * Holds the resolver for the `waitForInitialization_` promise.
- * @private @type {null|function():void}
- */
- this.finishInitialization_ = null;
-
- /**
- * Promise used to wait for the initialize() method to finish.
- * @private @type {!Promise<void>}
- */
- this.waitForInitialization_ =
- new Promise(resolve => this.finishInitialization_ = resolve);
-
// Subscribe to mount event as early as possible, but after the
// waitForInitialization_ above.
chrome.fileManagerPrivate.onMountCompleted.addListener(
this.onMountCompleted_.bind(this));
}
- /** @override */
- // @ts-ignore: error TS4122: This member cannot have a JSDoc comment with an
- // '@override' tag because it is not declared in the base class 'EventTarget'.
- getFuseBoxOnlyFilterEnabled() {
+ getFuseBoxOnlyFilterEnabled(): boolean {
return false;
}
- /** @override */
- // @ts-ignore: error TS4122: This member cannot have a JSDoc comment with an
- // '@override' tag because it is not declared in the base class 'EventTarget'.
- getMediaStoreFilesOnlyFilterEnabled() {
+ getMediaStoreFilesOnlyFilterEnabled(): boolean {
return false;
}
- /** @override */
- // @ts-ignore: error TS4122: This member cannot have a JSDoc comment with an
- // '@override' tag because it is not declared in the base class 'EventTarget'.
- dispose() {}
+ dispose(): void {}
/**
* Invoked when the drive connection status is changed.
- * @private
*/
- onDriveConnectionStatusChanged_() {
+ private onDriveConnectionStatusChanged_() {
chrome.fileManagerPrivate.getDriveConnectionState(state => {
this.driveConnectionState_ = state;
dispatchSimpleEvent(this, 'drive-connection-changed');
});
}
- /** @override */
- // @ts-ignore: error TS4122: This member cannot have a JSDoc comment with an
- // '@override' tag because it is not declared in the base class 'EventTarget'.
- getDriveConnectionState() {
+ getDriveConnectionState(): chrome.fileManagerPrivate.DriveConnectionState {
return this.driveConnectionState_;
}
/**
* Adds new volume info from the given volumeMetadata. If the corresponding
* volume info has already been added, the volumeMetadata is ignored.
- * @param {!import("../../externs/volume_info.js").VolumeInfo} volumeInfo
- * @return {!import("../../externs/volume_info.js").VolumeInfo}
- * @private
*/
- addVolumeInfo_(volumeInfo) {
+ private addVolumeInfo_(volumeInfo: VolumeInfo): VolumeInfo {
const volumeType = volumeInfo.volumeType;
// We don't show Downloads and Drive on volume list if they have
@@ -159,9 +151,8 @@
/**
* Initializes mount points.
- * @return {!Promise<void>}
*/
- async initialize() {
+ async initialize(): Promise<void> {
let finished = false;
/**
* Resolves the initialization promise to unblock any code awaiting for
@@ -173,28 +164,26 @@
}
finished = true;
console.warn('Volumes initialization finished');
- // @ts-ignore: error TS2554: Expected 1 arguments, but got 0.
- this.finishInitialization_();
+ if (this.finishInitialization_) {
+ this.finishInitialization_();
+ }
};
try {
console.warn('Getting volumes');
- let volumeMetadataList =
+ let volumeMetadataList: chrome.fileManagerPrivate.VolumeMetadata[] =
await promisify(chrome.fileManagerPrivate.getVolumeMetadataList);
if (!volumeMetadataList) {
console.warn('Cannot get volumes');
finishInitialization();
return;
}
- // @ts-ignore: error TS7006: Parameter 'volume' implicitly has an 'any'
- // type.
volumeMetadataList = volumeMetadataList.filter(volume => !volume.hidden);
console.debug(`There are ${volumeMetadataList.length} volumes`);
let counter = 0;
// Create VolumeInfo for each volume.
- // @ts-ignore: error TS7006: Parameter 'idx' implicitly has an 'any' type.
volumeMetadataList.map(async (volumeMetadata, idx) => {
const volumeId = volumeMetadata.volumeId;
let volumeInfo = null;
@@ -239,10 +228,9 @@
/**
* Event handler called when some volume was mounted or unmounted.
- * @param {chrome.fileManagerPrivate.MountCompletedEvent} event
- * @private
*/
- async onMountCompleted_(event) {
+ private async onMountCompleted_(
+ event: chrome.fileManagerPrivate.MountCompletedEvent) {
// Wait for the initialization to guarantee that the initialize() runs for
// some volumes before any mount event, because the mounted volume can be
// unresponsive, getting stuck when resolving the root in the method
@@ -271,11 +259,10 @@
try {
volumeInfo =
await volumeManagerUtil.createVolumeInfo(volumeMetadata);
- } catch (error) {
+ } catch (error: any) {
console.warn(
'Unable to create volumeInfo for ' +
`${volumeId} mounted on ${sourcePath}.` +
- // @ts-ignore: error TS18046: 'error' is of type 'unknown'.
`Mount status: ${status}. Error: ${error.stack || error}.`);
this.finishRequest_(requestKey, status);
throw (error);
@@ -291,9 +278,8 @@
console.debug(`Cannot mount '${sourcePath}': Already mounted as '${
volumeId}'`);
const navigationEvent =
- new Event(VolumeManagerCommon.VOLUME_ALREADY_MOUNTED);
- // @ts-ignore: error TS2339: Property 'volumeId' does not exist on
- // type 'Event'.
+ new Event(VolumeManagerCommon.VOLUME_ALREADY_MOUNTED) as
+ VolumeAlreadyMountedEvent;
navigationEvent.volumeId = volumeId;
this.dispatchEvent(navigationEvent);
this.finishRequest_(requestKey, status);
@@ -345,39 +331,29 @@
/**
* Creates string to match mount events with requests.
- * @param {string} requestType 'mount' | 'unmount'. TODO(hidehiko): Replace by
- * enum.
- * @param {string} argument Argument describing the request, eg. source file
+ * @param requestType 'mount' | 'unmount'. TODO(hidehiko): Replace by enum.
+ * @param argument Argument describing the request, eg. source file
* path of the archive to be mounted, or a volumeId for unmounting.
- * @return {string} Key for |this.requests_|.
- * @private
+ * @return Key for |this.requests_|.
*/
- makeRequestKey_(requestType, argument) {
+ private makeRequestKey_(requestType: string, argument: string): string {
return requestType + ':' + argument;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'password' implicitly has an 'any'
- // type.
- async mountArchive(fileUrl, password) {
- const path =
+ async mountArchive(fileUrl: string, password?: string): Promise<VolumeInfo> {
+ const path: string =
await promisify(chrome.fileManagerPrivate.addMount, fileUrl, password);
console.debug(`Mounting '${path}'`);
const key = this.makeRequestKey_('mount', path);
return this.startRequest_(key);
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'fileUrl' implicitly has an 'any' type.
- async cancelMounting(fileUrl) {
+ async cancelMounting(fileUrl: string): Promise<void> {
console.debug(`Cancelling mounting archive at '${fileUrl}'`);
return promisify(chrome.fileManagerPrivate.cancelMounting, fileUrl);
}
- /** @override */
- // @ts-ignore: error TS7031: Binding element 'volumeId' implicitly has an
- // 'any' type.
- async unmount({volumeId}) {
+ async unmount({volumeId}: VolumeInfo): Promise<void> {
console.debug(`Unmounting '${volumeId}'`);
const key = this.makeRequestKey_('unmount', volumeId);
const request = this.startRequest_(key);
@@ -385,17 +361,12 @@
await request;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'volumeInfo' implicitly has an 'any'
- // type.
- configure(volumeInfo) {
+ configure(volumeInfo: VolumeInfo): Promise<void> {
return promisify(
chrome.fileManagerPrivate.configureVolume, volumeInfo.volumeId);
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'entry' implicitly has an 'any' type.
- getVolumeInfo(entry) {
+ getVolumeInfo(entry: Entry|FilesAppEntry): VolumeInfo|null {
if (!entry) {
console.warn(`Invalid entry passed to getVolumeInfo: ${entry}`);
return null;
@@ -419,10 +390,8 @@
return null;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'volumeType' implicitly has an 'any'
- // type.
- getCurrentProfileVolumeInfo(volumeType) {
+ getCurrentProfileVolumeInfo(volumeType: VolumeManagerCommon.VolumeType):
+ VolumeInfo|null {
for (let i = 0; i < this.volumeInfoList.length; i++) {
const volumeInfo = this.volumeInfoList.item(i);
if (volumeInfo.profile.isCurrentProfile &&
@@ -433,9 +402,7 @@
return null;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'entry' implicitly has an 'any' type.
- getLocationInfo(entry) {
+ getLocationInfo(entry: Entry|FilesAppEntry): EntryLocation|null {
if (!entry) {
console.warn(`Invalid entry passed to getLocationInfo: ${entry}`);
return null;
@@ -444,19 +411,20 @@
const volumeInfo = this.getVolumeInfo(entry);
if (isFakeEntry(entry)) {
+ const rootType = getRootType(entry);
+ assert(rootType);
+
// Aggregated views like RECENTS and TRASH exist as fake entries but may
// actually defer their logic to some underlying implementation or
// delegate to the location filesystem.
let isReadOnly = true;
- if (entry.rootType === VolumeManagerCommon.RootType.RECENT ||
- entry.rootType === VolumeManagerCommon.RootType.TRASH) {
+ if (rootType === VolumeManagerCommon.RootType.RECENT ||
+ rootType === VolumeManagerCommon.RootType.TRASH) {
isReadOnly = false;
}
return new EntryLocationImpl(
- // @ts-ignore: error TS2345: Argument of type 'VolumeInfo | null' is
- // not assignable to parameter of type 'VolumeInfo'.
- volumeInfo, assert(entry.rootType),
- true /* The entry points a root directory. */, isReadOnly);
+ volumeInfo, rootType, true /* The entry points a root directory. */,
+ isReadOnly);
}
if (!volumeInfo) {
@@ -544,8 +512,9 @@
return null;
}
} else {
- rootType = VolumeManagerCommon.getRootTypeFromVolumeType(
- assert(volumeInfo.volumeType));
+ assert(volumeInfo.volumeType);
+ rootType =
+ VolumeManagerCommon.getRootTypeFromVolumeType(volumeInfo.volumeType);
isRootEntry = isSameEntry(entry, volumeInfo.fileSystem.root);
// Although "Play files" root directory is writable in file system level,
// we prohibit write operations on it in the UI level to avoid confusion.
@@ -563,10 +532,7 @@
return new EntryLocationImpl(volumeInfo, rootType, isRootEntry, isReadOnly);
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'devicePath' implicitly has an 'any'
- // type.
- findByDevicePath(devicePath) {
+ findByDevicePath(devicePath: string): VolumeInfo|null {
for (let i = 0; i < this.volumeInfoList.length; i++) {
const volumeInfo = this.volumeInfoList.item(i);
if (volumeInfo.devicePath && volumeInfo.devicePath === devicePath) {
@@ -576,10 +542,7 @@
return null;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'volumeId' implicitly has an 'any'
- // type.
- whenVolumeInfoReady(volumeId) {
+ whenVolumeInfoReady(volumeId: string): Promise<VolumeInfo> {
return new Promise((fulfill) => {
const handler = () => {
const index = this.volumeInfoList.findIndex(volumeId);
@@ -593,30 +556,27 @@
});
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'callback' implicitly has an 'any'
- // type.
- getDefaultDisplayRoot(callback) {
+ getDefaultDisplayRoot(
+ callback: ((arg0: DirectoryEntry|FilesAppDirEntry|null) => void)) {
console.warn('Unexpected call to VolumeManagerImpl.getDefaultDisplayRoot');
callback(null);
}
/**
- * @param {string} key Key produced by |makeRequestKey_|.
- * @return {!Promise<!import("../../externs/volume_info.js").VolumeInfo>}
- * Fulfilled on success, otherwise rejected with a
+ * @param key Key produced by |makeRequestKey_|.
+ * @return Fulfilled on success, otherwise rejected with a
* VolumeManagerCommon.VolumeError.
- * @private
*/
- startRequest_(key) {
+ private startRequest_(key: string): Promise<VolumeInfo> {
return new Promise((successCallback, errorCallback) => {
if (key in this.requests_) {
- const request = this.requests_[key];
- request.successCallbacks.push(successCallback);
+ const request = this.requests_[key]!;
+ request.successCallbacks.push(
+ successCallback as RequestSuccessCallback);
request.errorCallbacks.push(errorCallback);
} else {
this.requests_[key] = {
- successCallbacks: [successCallback],
+ successCallbacks: [successCallback as RequestSuccessCallback],
errorCallbacks: [errorCallback],
timeout: setTimeout(
@@ -628,79 +588,58 @@
/**
* Called if no response received in |TIMEOUT|.
- * @param {string} key Key produced by |makeRequestKey_|.
- * @private
+ * @param key Key produced by |makeRequestKey_|.
*/
- onTimeout_(key) {
+ private onTimeout_(key: string) {
this.invokeRequestCallbacks_(
- this.requests_[key], VolumeManagerCommon.VolumeError.TIMEOUT);
+ this.requests_[key]!, VolumeManagerCommon.VolumeError.TIMEOUT);
delete this.requests_[key];
}
/**
- * @param {string} key Key produced by |makeRequestKey_|.
- * @param {!VolumeManagerCommon.VolumeError|string} status Status received
- * from the API.
- * @param {import("../../externs/volume_info.js").VolumeInfo=} opt_volumeInfo
- * Volume info of the mounted volume.
- * @private
+ * @param key Key produced by |makeRequestKey_|.
+ * @param status Status received from the API.
+ * @param volumeInfo Volume info of the mounted volume.
*/
- finishRequest_(key, status, opt_volumeInfo) {
+ private finishRequest_(
+ key: string, status: VolumeManagerCommon.VolumeError|string,
+ volumeInfo?: VolumeInfo) {
const request = this.requests_[key];
if (!request) {
return;
}
clearTimeout(request.timeout);
- this.invokeRequestCallbacks_(request, status, opt_volumeInfo);
+ this.invokeRequestCallbacks_(request, status, volumeInfo);
delete this.requests_[key];
}
/**
- * @param {Object} request Structure created in |startRequest_|.
- * @param {!VolumeManagerCommon.VolumeError|string} status If status ===
- * 'success' success callbacks are called.
- * @param {import("../../externs/volume_info.js").VolumeInfo=} opt_volumeInfo
- * Volume info of the mounted volume.
- * @private
+ * @param request Structure created in |startRequest_|.
+ * @param status If status === 'success' success callbacks are called.
+ * @param volumeInfo Volume info of the mounted volume.
*/
- invokeRequestCallbacks_(request, status, opt_volumeInfo) {
- // @ts-ignore: error TS7006: Parameter 'args' implicitly has an 'any' type.
- const callEach = (callbacks, self, args) => {
- for (let i = 0; i < callbacks.length; i++) {
- callbacks[i].apply(self, args);
- }
- };
-
+ private invokeRequestCallbacks_(
+ request: Request, status: VolumeManagerCommon.VolumeError,
+ volumeInfo?: VolumeInfo) {
if (status === 'success') {
- // @ts-ignore: error TS2339: Property 'successCallbacks' does not exist on
- // type 'Object'.
- callEach(request.successCallbacks, this, [opt_volumeInfo]);
+ request.successCallbacks.map(cb => cb(volumeInfo));
+
} else {
volumeManagerUtil.validateError(status);
- // @ts-ignore: error TS2339: Property 'errorCallbacks' does not exist on
- // type 'Object'.
- callEach(request.errorCallbacks, this, [status]);
+ request.errorCallbacks.map(cb => cb(status));
}
}
- /** @override */
- // @ts-ignore: error TS4122: This member cannot have a JSDoc comment with an
- // '@override' tag because it is not declared in the base class 'EventTarget'.
- hasDisabledVolumes() {
+ hasDisabledVolumes(): boolean {
return false;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'volume' implicitly has an 'any' type.
- isDisabled(volume) {
+ isDisabled(_volume: VolumeManagerCommon.VolumeType): boolean {
return false;
}
- /** @override */
- // @ts-ignore: error TS7006: Parameter 'volumeInfo' implicitly has an 'any'
- // type.
- isAllowedVolume(volumeInfo) {
+ isAllowedVolume(_volumeInfo: VolumeInfo): boolean {
return true;
}
}
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 3155563..6a7ccb6 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -381,7 +381,7 @@
util.getRootTypeLabel = locationInfo => {
switch (locationInfo.rootType) {
case VolumeManagerCommon.RootType.DOWNLOADS:
- return locationInfo.volumeInfo.label;
+ return locationInfo.volumeInfo?.label ?? '';
case VolumeManagerCommon.RootType.DRIVE:
return str('DRIVE_MY_DRIVE_LABEL');
case VolumeManagerCommon.RootType.SHARED_DRIVE:
@@ -418,7 +418,7 @@
case VolumeManagerCommon.RootType.MEDIA_VIEW:
const mediaViewRootType =
VolumeManagerCommon.getMediaViewRootTypeFromVolumeId(
- locationInfo.volumeInfo.volumeId);
+ locationInfo.volumeInfo?.volumeId || '');
switch (mediaViewRootType) {
case VolumeManagerCommon.MediaViewRootType.IMAGES:
return str('MEDIA_VIEW_IMAGES_ROOT_LABEL');
@@ -430,7 +430,7 @@
return str('MEDIA_VIEW_DOCUMENTS_ROOT_LABEL');
}
console.error('Unsupported media view root type: ' + mediaViewRootType);
- return locationInfo.volumeInfo.label;
+ return locationInfo.volumeInfo?.label ?? '';
case VolumeManagerCommon.RootType.ARCHIVE:
case VolumeManagerCommon.RootType.REMOVABLE:
case VolumeManagerCommon.RootType.MTP:
@@ -439,10 +439,10 @@
case VolumeManagerCommon.RootType.DOCUMENTS_PROVIDER:
case VolumeManagerCommon.RootType.SMB:
case VolumeManagerCommon.RootType.GUEST_OS:
- return locationInfo.volumeInfo.label;
+ return locationInfo.volumeInfo?.label ?? '';
default:
console.error('Unsupported root type: ' + locationInfo.rootType);
- return locationInfo.volumeInfo.label;
+ return locationInfo.volumeInfo?.label ?? '';
}
};
diff --git a/ui/file_manager/file_manager/externs/entry_location.js b/ui/file_manager/file_manager/externs/entry_location.js
index 1a12444..4324e44 100644
--- a/ui/file_manager/file_manager/externs/entry_location.js
+++ b/ui/file_manager/file_manager/externs/entry_location.js
@@ -13,7 +13,7 @@
constructor() {
/**
* Volume information.
- * @type {import("./volume_info.js").VolumeInfo}
+ * @type {?import("./volume_info.js").VolumeInfo}
*/
this.volumeInfo;
diff --git a/ui/file_manager/file_manager/externs/volume_manager.js b/ui/file_manager/file_manager/externs/volume_manager.js
index b4a3028..66cbc75 100644
--- a/ui/file_manager/file_manager/externs/volume_manager.js
+++ b/ui/file_manager/file_manager/externs/volume_manager.js
@@ -202,7 +202,7 @@
/**
* Obtains the default display root entry.
- * @param {function((DirectoryEntry|FilesAppDirEntry)):void} callback
+ * @param {function((DirectoryEntry|FilesAppDirEntry|null)):void} callback
* Callback passed the default display root.
*/
// @ts-ignore: error TS6133: 'callback' is declared but its value is never
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.ts b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.ts
index 597a2ac..4b355130 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.ts
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.ts
@@ -1174,6 +1174,7 @@
}
const sourceUrls = (clipboardData.getData('fs/sources') || '').split('\n');
+ assert(destinationLocationInfo.volumeInfo);
if (this.getSourceRootUrl_(
clipboardData, this.getDragAndDropGlobalData_()) !==
destinationLocationInfo.volumeInfo.fileSystem.root.toURL()) {
@@ -1391,6 +1392,7 @@
}
// TODO(mtomasz): Use volumeId instead of comparing roots, as soon as
// volumeId gets unique.
+ assert(destinationLocationInfo.volumeInfo);
if (this.getSourceRootUrl_(event.dataTransfer!, dragAndDropData) ===
destinationLocationInfo.volumeInfo.fileSystem.root.toURL() &&
!event.ctrlKey) {
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index 9745d2e..6feab68 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -23,7 +23,6 @@
"file_manager/background/js/runtime_loaded_test_util.js",
"file_manager/background/js/test_util.js",
"file_manager/background/js/test_util_base.js",
- "file_manager/background/js/volume_manager_impl.js",
"file_manager/background/js/volume_manager_util.js",
# Files Common:
@@ -295,6 +294,7 @@
"file_manager/background/js/volume_info_impl.ts",
"file_manager/background/js/volume_info_list_impl.ts",
"file_manager/background/js/volume_manager_factory.ts",
+ "file_manager/background/js/volume_manager_impl.ts",
# Foreground.
"file_manager/foreground/js/file_transfer_controller.ts",