// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type {FilesAppEntry} from '../common/js/files_app_entry_types.js';
import type {DialogType} from '../common/js/shared_types.js';
import type {RootType, VolumeType} from '../common/js/volume_manager_types.js';
import type {MetadataItem} from '../foreground/js/metadata/metadata_item.js';
export {DialogType} from '../common/js/shared_types.js';
export enum EntryType {
// Entries from the FileSystem API.
FS_API = 'FS_API',
// The root of a volume is an Entry from the FileSystem API, but it aggregates
// more data from the volume.
VOLUME_ROOT = 'VOLUME_ROOT',
// A directory-like entry to aggregate other entries.
ENTRY_LIST = 'ENTRY_LIST',
// Placeholder that is replaced for another entry, for Crostini/GuestOS.
PLACEHOLDER = 'PLACEHOLDER',
// Root for the Trash.
TRASH = 'TRASH',
// Root for the Recent.
RECENT = 'RECENT',
// A folder-like that doesn't have an entry linked to it.
MATERIALIZED_VIEW = 'MATERIALIZED_VIEW',
}
/**
* The data for each individual file/entry.
*/
export interface FileData {
/** `key` is the file URL. */
key: FileKey;
fullPath: string;
entry?: Entry|FilesAppEntry;
/**
* `icon` can be either a string or a IconSet which is an object including
* both high/low DPI icon data.
*/
icon: string|chrome.fileManagerPrivate.IconSet;
label: string;
volumeId: VolumeId|null;
rootType: RootType|null;
metadata: MetadataItem;
isDirectory: boolean;
type: EntryType;
isRootEntry: boolean;
isEjectable: boolean;
canExpand: boolean;
/**
* TODO(b/271485133): `children` here only store sub directories for now, it
* should store all children including files, it's up to the container to do
* filter and sorting if needed.
*/
children: FileKey[];
expanded: boolean;
disabled: boolean;
}
/**
* A stronger type for identifying an entry.
* Currently entry is identified by its URL as string.
*
* NOTE: Fake entry, as in, entries implemented directly in JS/TS are identified
* by a made up URL like:
* fake-entry://recent
* fake-entry://trash
*/
export type FileKey = string;
/**
* A stronger type for identifying a volume.
*/
export type VolumeId = string;
/**
* Describes each part of the path, as in each parent folder and/or root volume.
*/
export interface PathComponent {
name: string;
label: string;
key: FileKey;
}
/**
* The status of a property, for properties that have their state updated via
* asynchronous steps.
*/
export enum PropStatus {
STARTED = 'STARTED',
// Finished:
SUCCESS = 'SUCCESS',
ERROR = 'ERROR',
}
/**
* Task type is the source of the task, or what type of the app is this type
* from. It has to match the `taskType` returned in the FileManagerPrivate.
*
* For more details see //chrome/browser/ash/file_manager/file_tasks.h
*/
export enum FileTaskType {
UNKNOWN = '',
// The task is from a chrome app/extension that has File Browser Handler in
// its manifest.
FILE = 'file',
// The task is from a chrome app/extension that has File Handler in its
// manifest.
APP = 'app',
// The task is from an Android app.
ARC = 'arc',
// The task is from a Crostini app.
CROSTINI = 'crostini',
// The task is from a Parallels app.
PLUGIN_VM = 'pluginvm',
// The task is from a Web app/PWA/SWA.
WEB = 'web',
}
/**
* Task Descriptor it's the unique identified for a Task.
*
* For more details see //chrome/browser/ash/file_manager/file_tasks.h
*/
export interface FileTaskDescriptor {
appId: string;
taskType: FileTaskType;
actionId: string;
}
/**
* UI representation for File Task.
* NOTE: This is slightly different from the FileTask from the
* FileManagerPrivate API. Here the task is enhanced to deal with different
* displaying icons and labels.
* TODO(lucmult): Change isDefault and isGenericFileHandler to boolean when
* non-Store version doesn't have to be supported anymore.
*/
export interface FileTask {
descriptor: FileTaskDescriptor;
title: string;
iconUrl: string|undefined;
iconType: string;
isDefault: boolean|undefined;
isGenericFileHandler: boolean|undefined;
isDlpBlocked: boolean|undefined;
}
/**
* Container for FileTask.
* `defaultHandlerPolicy` is only set if the user can't change the default
* handler due to a policy, either the policy forces the default handler or
* the policy is incorrect, but we still don't allow user to change the
* default.
*
* TODO(lucmult): keys might not be needed here.
*/
export interface FileTasks {
tasks: FileTask[];
policyDefaultHandlerStatus:
chrome.fileManagerPrivate.PolicyDefaultHandlerStatus|undefined;
defaultTask: (FileTask|undefined);
status: PropStatus;
}
/**
* Launch parameters for the file manager.
*/
export interface LaunchParams {
dialogType: DialogType|undefined;
}
/**
* This represents the entries currently selected, out of the entries
* displayed in the file list/grid.
*/
export interface Selection {
keys: FileKey[];
dirCount: number;
fileCount: number;
hostedCount: number|undefined;
offlineCachedCount: number;
fileTasks: FileTasks;
}
/**
* Represents the entries displayed in the file list/grid.
*/
export interface DirectoryContent {
status: PropStatus;
keys: FileKey[];
}
/**
* The current directory.
* The directory is only effectively active when the `status` is SUCCESS.
*/
export interface CurrentDirectory {
status: PropStatus;
key: FileKey;
pathComponents: PathComponent[];
content: DirectoryContent;
selection: Selection;
rootType: RootType|undefined;
hasDlpDisabledFiles: boolean;
}
/**
* Enumeration of all supported search locations. If new location is added,
* please update this enum.
*/
export enum SearchLocation {
EVERYWHERE = 'everywhere',
ROOT_FOLDER = 'root_folder',
THIS_FOLDER = 'this_folder',
}
/**
* Enumeration of all supported how-recent time spans.
*/
export enum SearchRecency {
ANYTIME = 'anytime',
TODAY = 'today',
YESTERDAY = 'yesterday',
LAST_WEEK = 'last_week',
LAST_MONTH = 'last_month',
LAST_YEAR = 'last_year',
}
/**
* The options used by the file search operation.
*/
export interface SearchOptions {
location: SearchLocation;
recency: SearchRecency;
fileCategory: chrome.fileManagerPrivate.FileCategory;
}
/**
* Data for search. It should be empty `{}` when the user isn't searching.
*/
export interface SearchData {
status: PropStatus|undefined;
query: string|undefined;
options: SearchOptions|undefined;
}
/**
* Used to group volumes in the navigation tree.
* Sections:
* - TOP: Recents, Shortcuts.
* - MY_FILES: My Files (which includes Downloads, Crostini and Arc++ as
* its children).
* - TRASH: trash.
* - GOOGLE_DRIVE: Just Google Drive.
* - ODFS: Just ODFS.
* - CLOUD: All other cloud: SMBs, FSPs and Documents Providers.
* - ANDROID_APPS: ANDROID picker apps.
* - REMOVABLE: Archives, MTPs, Media Views and Removables.
*/
export enum NavigationSection {
TOP = 'top',
MY_FILES = 'my_files',
GOOGLE_DRIVE = 'google_drive',
ODFS = 'odfs',
CLOUD = 'cloud',
TRASH = 'trash',
ANDROID_APPS = 'android_apps',
REMOVABLE = 'removable',
}
export enum NavigationType {
SHORTCUT = 'shortcut',
VOLUME = 'volume',
RECENT = 'recent',
CROSTINI = 'crostini',
GUEST_OS = 'guest_os',
ENTRY_LIST = 'entry_list',
DRIVE = 'drive',
ANDROID_APPS = 'android_apps',
TRASH = 'trash',
// Materialized view is used for Recent and in the future for Search.
MATERIALIZED_VIEW = 'materialized_view',
}
/**
* The key of navigation item, it could be:
* * FileKey: the navigation is backed up by a real file entry.
* * string: the navigation is backed up by others (e.g. androids_apps).
*/
export type NavigationKey = FileKey|string;
/**
* This represents the navigation root node, it can be backed up by an file
* entry or an Android app package (e.g. for android_apps type). If its type
* is android_apps, the `key` filed will be android app's package name, not a
* file key.
*/
export interface NavigationRoot {
key: NavigationKey;
section: NavigationSection;
type: NavigationType;
separator: boolean;
}
export interface NavigationTree {
/** It's just a ordered array with NavigationRoot. */
roots: NavigationRoot[];
}
/**
* This carries the same information as VolumeInfo, which is very similar to
* fileManagerPrivate.VolumeMetadata.
*
* The property names are identical to VolumeInfo to simplify the migration.
* Notable differences: missing the properties: profile, remoteMountPath.
*
* When the volume has an unrecognized file system, it's still mounted here,
* but with `error`=="unknown".
*/
export interface Volume {
volumeId: VolumeId;
volumeType: VolumeType;
rootKey: FileKey|undefined;
status: PropStatus;
label: string;
error: string|undefined;
deviceType: chrome.fileManagerPrivate.DeviceType|undefined;
devicePath: string|undefined;
isReadOnly: boolean;
isReadOnlyRemovableDevice: boolean;
providerId: string|undefined;
configurable: boolean;
watchable: boolean;
source: chrome.fileManagerPrivate.Source|undefined;
diskFileSystemType: (string|undefined);
iconSet: chrome.fileManagerPrivate.IconSet|undefined;
driveLabel: string|undefined;
vmType: chrome.fileManagerPrivate.VmType|undefined;
isDisabled: boolean;
prefixKey: FileKey|undefined;
isInteractive: boolean;
}
export type VolumeMap = Record<VolumeId, Volume>;
/**
* This carries the state related to physical user device.
*/
export interface Device {
connection: chrome.fileManagerPrivate.DeviceConnectionState;
}
/**
* This carries the state related to the underlying Drive connection status.
* This differs from the device connection state as the Drive can also be in a
* effectively paused state when on a metered network.
*/
export interface Drive {
connectionType: chrome.fileManagerPrivate.DriveConnectionStateType;
offlineReason: chrome.fileManagerPrivate.DriveOfflineReason|undefined;
}
/**
* An extension of `chrome.fileManagerPrivate.AndroidApp`. The only difference
* from the private API AndroidApp is this one adds an union type `icon`. This
* is because `iconSet` can generate a "none" background sometimes, in this
* case we need a backup icon instead.
*
* Note: we keep `iconSet` here to be compatible with the original AndroidApp
* type because private API `selectAndroidPickerApp` still requires the
* original type. For other use cases, we can ignore `iconSet` and just use
* `icon`.
*/
export interface AndroidApp {
name: string;
packageName: string;
activityName: string;
iconSet?: chrome.fileManagerPrivate.IconSet|undefined;
icon: string|chrome.fileManagerPrivate.IconSet;
}
/**
* A view behaves like a folder, as in, it's a collection of FileData.
*
* Its content comes from the File Index.
*/
export interface MaterializedView {
id: string;
key: FileKey;
label: string;
icon: string;
isRoot: boolean;
}
/**
* Files app's state.
*/
export interface State {
allEntries: Record<FileKey, FileData>;
currentDirectory: CurrentDirectory|undefined;
device: Device;
drive: Drive;
launchParams: LaunchParams;
search: SearchData|undefined;
navigation: NavigationTree;
volumes: Record<VolumeId, Volume>;
uiEntries: FileKey[];
folderShortcuts: FileKey[];
androidApps: Record<string, AndroidApp>;
bulkPinning?: chrome.fileManagerPrivate.BulkPinProgress;
preferences?: chrome.fileManagerPrivate.Preferences;
materializedViews: MaterializedView[];
}