github.com/minio/console@v1.4.1/web-app/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2022 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import { createSlice, PayloadAction } from "@reduxjs/toolkit";
    18  import { IFileItem, ObjectBrowserState } from "./types";
    19  import {
    20    BucketObjectItem,
    21    IRestoreLocalObjectList,
    22  } from "../Buckets/ListBuckets/Objects/ListObjects/types";
    23  import {
    24    BucketVersioningResponse,
    25    GetBucketRetentionConfig,
    26  } from "api/consoleApi";
    27  import { AppState } from "store";
    28  
    29  const defaultRewind = {
    30    rewindEnabled: false,
    31    bucketToRewind: "",
    32    dateToRewind: null,
    33  };
    34  
    35  const initialState: ObjectBrowserState = {
    36    selectedBucket: "",
    37    versionsMode: false,
    38    reloadObjectsList: false,
    39    requestInProgress: true,
    40    objectDetailsOpen: false,
    41    loadingVersions: true,
    42    loadingObjectInfo: true,
    43    connectionError: false,
    44    rewind: {
    45      ...defaultRewind,
    46    },
    47    objectManager: {
    48      objectsToManage: [],
    49      managerOpen: false,
    50      newItems: false,
    51      startedItems: [],
    52      currentDownloads: [],
    53      currentUploads: [],
    54    },
    55    searchObjects: "",
    56    versionedFile: "",
    57    searchVersions: "",
    58    selectedVersion: "",
    59    showDeleted: false,
    60    selectedInternalPaths: null,
    61    simplePath: null,
    62    // object browser
    63    records: [],
    64    loadingVersioning: true,
    65    versionInfo: {},
    66    lockingEnabled: false,
    67    loadingLocking: true,
    68    selectedObjects: [],
    69    downloadRenameModal: null,
    70    selectedPreview: null,
    71    previewOpen: false,
    72    shareFileModalOpen: false,
    73    anonymousAccessOpen: false,
    74    retentionConfig: {
    75      mode: undefined,
    76      unit: undefined,
    77      validity: 0,
    78    },
    79    longFileOpen: false,
    80    maxShareLinkExpTime: 0,
    81  };
    82  
    83  export const objectBrowserSlice = createSlice({
    84    name: "objectBrowser",
    85    initialState,
    86    reducers: {
    87      setRewindEnable: (
    88        state,
    89        action: PayloadAction<{
    90          state: boolean;
    91          bucket: string;
    92          dateRewind: any;
    93        }>,
    94      ) => {
    95        state.rewind.rewindEnabled = action.payload.state;
    96        state.rewind.bucketToRewind = action.payload.bucket;
    97        state.rewind.dateToRewind = action.payload.dateRewind;
    98      },
    99      resetRewind: (state) => {
   100        state.rewind.rewindEnabled = false;
   101        state.rewind.bucketToRewind = "";
   102        state.rewind.dateToRewind = null;
   103      },
   104      setVersionsModeEnabled: (
   105        state,
   106        action: PayloadAction<{
   107          status: boolean;
   108          objectName?: string;
   109        }>,
   110      ) => {
   111        let objN = "";
   112        if (action.payload.objectName) {
   113          objN = action.payload.objectName;
   114        }
   115        const objectN = !action.payload.status ? "" : objN;
   116        state.versionsMode = action.payload.status;
   117        state.versionedFile = objectN;
   118        state.selectedVersion = "";
   119      },
   120      setNewObject: (state, action: PayloadAction<IFileItem>) => {
   121        state.objectManager.objectsToManage.push(action.payload);
   122        state.objectManager.newItems = true;
   123      },
   124      updateProgress: (
   125        state,
   126        action: PayloadAction<{
   127          instanceID: string;
   128          progress: number;
   129        }>,
   130      ) => {
   131        const itemUpdate = state.objectManager.objectsToManage.findIndex(
   132          (item) => item.instanceID === action.payload.instanceID,
   133        );
   134  
   135        if (itemUpdate === -1) {
   136          return;
   137        }
   138  
   139        state.objectManager.objectsToManage[itemUpdate].percentage =
   140          action.payload.progress;
   141        state.objectManager.objectsToManage[itemUpdate].waitingForFile = false;
   142      },
   143      completeObject: (state, action: PayloadAction<string>) => {
   144        const objectToComplete = state.objectManager.objectsToManage.findIndex(
   145          (item) => item.instanceID === action.payload,
   146        );
   147  
   148        if (objectToComplete === -1) {
   149          return;
   150        }
   151  
   152        state.objectManager.objectsToManage[objectToComplete].percentage = 100;
   153        state.objectManager.objectsToManage[objectToComplete].waitingForFile =
   154          false;
   155        state.objectManager.objectsToManage[objectToComplete].done = true;
   156  
   157        // We cancel from in-progress lists
   158        const type = state.objectManager.objectsToManage[objectToComplete].type;
   159        const ID = state.objectManager.objectsToManage[objectToComplete].ID;
   160  
   161        if (type === "download") {
   162          state.objectManager.currentDownloads =
   163            state.objectManager.currentDownloads.filter((item) => item !== ID);
   164        } else if (type === "upload") {
   165          state.objectManager.currentUploads =
   166            state.objectManager.currentUploads.filter((item) => item !== ID);
   167        }
   168      },
   169      failObject: (
   170        state,
   171        action: PayloadAction<{ instanceID: string; msg: string }>,
   172      ) => {
   173        const objectToFail = state.objectManager.objectsToManage.findIndex(
   174          (item) => item.instanceID === action.payload.instanceID,
   175        );
   176  
   177        state.objectManager.objectsToManage[objectToFail].failed = true;
   178        state.objectManager.objectsToManage[objectToFail].waitingForFile = false;
   179        state.objectManager.objectsToManage[objectToFail].done = true;
   180        state.objectManager.objectsToManage[objectToFail].errorMessage =
   181          action.payload.msg;
   182  
   183        // We cancel from in-progress lists
   184        const type = state.objectManager.objectsToManage[objectToFail].type;
   185        const ID = state.objectManager.objectsToManage[objectToFail].ID;
   186  
   187        if (type === "download") {
   188          state.objectManager.currentDownloads =
   189            state.objectManager.currentDownloads.filter((item) => item !== ID);
   190        } else if (type === "upload") {
   191          state.objectManager.currentUploads =
   192            state.objectManager.currentUploads.filter((item) => item !== ID);
   193        }
   194      },
   195      cancelObjectInList: (state, action: PayloadAction<string>) => {
   196        const objectToCancel = state.objectManager.objectsToManage.findIndex(
   197          (item) => item.instanceID === action.payload,
   198        );
   199  
   200        if (objectToCancel === -1) {
   201          return { ...state };
   202        }
   203  
   204        state.objectManager.objectsToManage[objectToCancel].cancelled = true;
   205        state.objectManager.objectsToManage[objectToCancel].done = true;
   206        state.objectManager.objectsToManage[objectToCancel].percentage = 0;
   207  
   208        // We cancel from in-progress lists
   209        const type = state.objectManager.objectsToManage[objectToCancel].type;
   210        const ID = state.objectManager.objectsToManage[objectToCancel].ID;
   211  
   212        if (type === "download") {
   213          state.objectManager.currentDownloads =
   214            state.objectManager.currentDownloads.filter((item) => item !== ID);
   215        } else if (type === "upload") {
   216          state.objectManager.currentUploads =
   217            state.objectManager.currentUploads.filter((item) => item !== ID);
   218        }
   219      },
   220      deleteFromList: (state, action: PayloadAction<string>) => {
   221        const notObject = state.objectManager.objectsToManage.filter(
   222          (element) => element.instanceID !== action.payload,
   223        );
   224  
   225        state.objectManager.objectsToManage = notObject;
   226        state.objectManager.managerOpen =
   227          notObject.length === 0 ? false : state.objectManager.managerOpen;
   228      },
   229      cleanList: (state) => {
   230        const nonCompletedList = state.objectManager.objectsToManage.filter(
   231          (item) => item.percentage !== 100,
   232        );
   233        state.objectManager.objectsToManage = nonCompletedList;
   234        state.objectManager.managerOpen =
   235          nonCompletedList.length === 0 ? false : state.objectManager.managerOpen;
   236        state.objectManager.newItems = false;
   237      },
   238      toggleList: (state) => {
   239        state.objectManager.managerOpen = !state.objectManager.managerOpen;
   240        state.objectManager.newItems = false;
   241      },
   242      openList: (state) => {
   243        state.objectManager.managerOpen = true;
   244      },
   245      closeList: (state) => {
   246        state.objectManager.managerOpen = false;
   247      },
   248      setSearchObjects: (state, action: PayloadAction<string>) => {
   249        state.searchObjects = action.payload;
   250      },
   251      setRequestInProgress: (state, action: PayloadAction<boolean>) => {
   252        state.requestInProgress = action.payload;
   253      },
   254      setSearchVersions: (state, action: PayloadAction<string>) => {
   255        state.searchVersions = action.payload;
   256      },
   257      setSelectedVersion: (state, action: PayloadAction<string>) => {
   258        state.selectedVersion = action.payload;
   259      },
   260      setShowDeletedObjects: (state, action: PayloadAction<boolean>) => {
   261        state.showDeleted = action.payload;
   262      },
   263      setLoadingVersions: (state, action: PayloadAction<boolean>) => {
   264        state.loadingVersions = action.payload;
   265      },
   266      setLoadingObjectInfo: (state, action: PayloadAction<boolean>) => {
   267        state.loadingObjectInfo = action.payload;
   268      },
   269      setObjectDetailsView: (state, action: PayloadAction<boolean>) => {
   270        state.objectDetailsOpen = action.payload;
   271        state.selectedInternalPaths = action.payload
   272          ? state.selectedInternalPaths
   273          : null;
   274      },
   275      setSelectedObjectView: (state, action: PayloadAction<string | null>) => {
   276        state.selectedInternalPaths = action.payload;
   277      },
   278      setSimplePathHandler: (state, action: PayloadAction<string>) => {
   279        state.simplePath = action.payload;
   280      },
   281      newDownloadInit: (state, action: PayloadAction<string>) => {
   282        state.objectManager.currentDownloads = [
   283          ...state.objectManager.currentDownloads,
   284          action.payload,
   285        ];
   286      },
   287      newUploadInit: (state, action: PayloadAction<string>) => {
   288        state.objectManager.currentUploads = [
   289          ...state.objectManager.currentUploads,
   290          action.payload,
   291        ];
   292      },
   293      setRecords: (state, action: PayloadAction<BucketObjectItem[]>) => {
   294        state.records = action.payload;
   295      },
   296      setLoadingVersioning: (state, action: PayloadAction<boolean>) => {
   297        state.loadingVersioning = action.payload;
   298      },
   299      setIsVersioned: (
   300        state,
   301        action: PayloadAction<BucketVersioningResponse>,
   302      ) => {
   303        state.versionInfo = action.payload;
   304      },
   305      setLockingEnabled: (state, action: PayloadAction<boolean | undefined>) => {
   306        state.lockingEnabled = action.payload;
   307      },
   308      setLoadingLocking: (state, action: PayloadAction<boolean>) => {
   309        state.loadingLocking = action.payload;
   310      },
   311      newMessage: (state, action: PayloadAction<BucketObjectItem[]>) => {
   312        state.records = [...state.records, ...action.payload];
   313      },
   314      resetMessages: (state) => {
   315        state.records = [];
   316      },
   317      setReloadObjectsList: (state, action: PayloadAction<boolean>) => {
   318        state.reloadObjectsList = action.payload;
   319  
   320        // If we initialize a request, then we must clean the records list
   321        if (action.payload) {
   322          state.records = [];
   323        }
   324      },
   325      setSelectedObjects: (state, action: PayloadAction<string[]>) => {
   326        state.selectedObjects = action.payload;
   327      },
   328      setDownloadRenameModal: (
   329        state,
   330        action: PayloadAction<BucketObjectItem | null>,
   331      ) => {
   332        state.downloadRenameModal = action.payload;
   333      },
   334      setSelectedPreview: (
   335        state,
   336        action: PayloadAction<BucketObjectItem | null>,
   337      ) => {
   338        state.selectedPreview = action.payload;
   339      },
   340      setPreviewOpen: (state, action: PayloadAction<boolean>) => {
   341        state.previewOpen = action.payload;
   342      },
   343      setShareFileModalOpen: (state, action: PayloadAction<boolean>) => {
   344        state.shareFileModalOpen = action.payload;
   345      },
   346      restoreLocalObjectList: (
   347        state,
   348        action: PayloadAction<IRestoreLocalObjectList>,
   349      ) => {
   350        const indexToReplace = state.records.findIndex(
   351          (element) => element.name === action.payload.prefix,
   352        );
   353  
   354        if (indexToReplace >= 0) {
   355          state.records[indexToReplace].delete_flag =
   356            action.payload.objectInfo.is_delete_marker;
   357          state.records[indexToReplace].size =
   358            action.payload.objectInfo.size || 0;
   359        }
   360      },
   361      setRetentionConfig: (
   362        state,
   363        action: PayloadAction<GetBucketRetentionConfig | null>,
   364      ) => {
   365        state.retentionConfig = action.payload;
   366      },
   367      setSelectedBucket: (state, action: PayloadAction<string>) => {
   368        state.selectedBucket = action.payload;
   369      },
   370      setLongFileOpen: (state, action: PayloadAction<boolean>) => {
   371        state.longFileOpen = action.payload;
   372      },
   373      setAnonymousAccessOpen: (state, action: PayloadAction<boolean>) => {
   374        state.anonymousAccessOpen = action.payload;
   375      },
   376      setMaxShareLinkExpTime: (state, action: PayloadAction<number>) => {
   377        state.maxShareLinkExpTime = action.payload;
   378      },
   379      errorInConnection: (state, action: PayloadAction<boolean>) => {
   380        state.connectionError = action.payload;
   381        if (action.payload) {
   382          state.requestInProgress = false;
   383          state.loadingObjectInfo = false;
   384          state.objectDetailsOpen = false;
   385        }
   386      },
   387    },
   388  });
   389  export const {
   390    setRewindEnable,
   391    resetRewind,
   392    setVersionsModeEnabled,
   393    setNewObject,
   394    updateProgress,
   395    completeObject,
   396    failObject,
   397    deleteFromList,
   398    cleanList,
   399    toggleList,
   400    openList,
   401    closeList,
   402    setSearchObjects,
   403    setRequestInProgress,
   404    cancelObjectInList,
   405    setSearchVersions,
   406    setSelectedVersion,
   407    setShowDeletedObjects,
   408    setLoadingVersions,
   409    setLoadingObjectInfo,
   410    setObjectDetailsView,
   411    setSelectedObjectView,
   412    setSimplePathHandler,
   413    newDownloadInit,
   414    newUploadInit,
   415    setRecords,
   416    resetMessages,
   417    setLoadingVersioning,
   418    setIsVersioned,
   419    setLoadingLocking,
   420    setLockingEnabled,
   421    newMessage,
   422    setSelectedObjects,
   423    setDownloadRenameModal,
   424    setSelectedPreview,
   425    setPreviewOpen,
   426    setShareFileModalOpen,
   427    setReloadObjectsList,
   428    restoreLocalObjectList,
   429    setRetentionConfig,
   430    setSelectedBucket,
   431    setLongFileOpen,
   432    setAnonymousAccessOpen,
   433    setMaxShareLinkExpTime,
   434    errorInConnection,
   435  } = objectBrowserSlice.actions;
   436  
   437  export const maxShareLinkExpTime = (state: AppState) =>
   438    state.objectBrowser.maxShareLinkExpTime;
   439  
   440  export default objectBrowserSlice.reducer;