diff --git a/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.resx b/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.resx index 2f22db0bc47..52c267f078a 100644 --- a/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.resx +++ b/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.resx @@ -318,4 +318,22 @@ New Location + + Name + + + Last Modified + + + Size + + + Parent Folder + + + Date Created + + + Sort + \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components.d.ts b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components.d.ts index 8ca677ad6da..8add285841a 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components.d.ts +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components.d.ts @@ -14,6 +14,9 @@ export namespace Components { interface DnnRmActionsBar { } interface DnnRmFilesPane { + /** + * Defines how much more pixels to load under the fold. + */ "preloadOffset": number; } interface DnnRmFolderList { @@ -131,6 +134,9 @@ declare namespace LocalJSX { interface DnnRmActionsBar { } interface DnnRmFilesPane { + /** + * Defines how much more pixels to load under the fold. + */ "preloadOffset"?: number; } interface DnnRmFolderList { diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-resource-manager/dnn-resource-manager.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-resource-manager/dnn-resource-manager.tsx index b6c8a127ad9..fc344dd7c94 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-resource-manager/dnn-resource-manager.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-resource-manager/dnn-resource-manager.tsx @@ -1,6 +1,7 @@ import { Component, Host, h, State, Watch, Prop } from '@stencil/core'; import state from "../../store/store"; import { LocalizationClient } from "../../services/LocalizationClient"; +import { sortField } from '../../enums/SortField'; const localStorageSplitWidthKey = "dnn-resource-manager-last-folders-width"; @Component({ @@ -30,9 +31,19 @@ export class DnnResourceManager { } componentWillLoad() { - this.localizationClient.getResources() - .then(resources => state.localization = resources) - .catch(error => console.error(error)); + return new Promise((resolve, reject) => { + this.localizationClient.getResources() + .then(resources => + { + state.localization = resources; + state.sortField = sortField.itemName; + resolve(); + }) + .catch(error => { + console.error(error); + reject(); + }); + }) } private splitView: HTMLDnnVerticalSplitviewElement; diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss index c98b4e45280..a6f62c226de 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss @@ -12,12 +12,46 @@ button{ border:0; padding:0; margin:0; + cursor: pointer; svg{ fill: var(--dnn-color-primary); } } .right-controls{ + display: flex; margin: 0 1em; + gap: 1em; + .sort{ + position: relative; + dnn-collapsible{ + position: absolute; + top: 100%; + right: 0; + background-color: white;; + &[expanded]{ + border: 1px solid lightgray; + box-shadow: 2px 2px 4px -2px; + } + .dropdown{ + display: flex; + flex-direction: column; + background-color: white;; + button{ + background-color:transparent; + border: none; + padding: 0.5em 1em; + margin: 0; + border-bottom: 1px solid lightgray; + white-space: nowrap; + svg{ + height: 1em; + width: 1em; + margin-right: 0.5em; + } + } + } + } + } } dnn-vertical-overflow-menu{ flex-grow: 1; diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.tsx index 5eb89da972c..bfd302fe7d3 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.tsx @@ -1,5 +1,6 @@ -import { Component, Host, h } from '@stencil/core'; +import { Component, Host, h, State } from '@stencil/core'; import state from '../../store/store'; +import { sortField, SortFieldInfo } from "../../enums/SortField"; @Component({ tag: 'dnn-rm-actions-bar', @@ -7,6 +8,8 @@ import state from '../../store/store'; shadow: true, }) export class DnnRmActionsBar { + + @State() sortDropdownExpanded: boolean = false; private changeLayout(): void { if (state.layout == "card"){ @@ -17,6 +20,31 @@ export class DnnRmActionsBar { state.layout = "card"; } + private renderSortButton(sortOption: SortFieldInfo){ + return( + + { + state.sortField = sortOption; + state.currentItems = {...state.currentItems, items: []}; + this.sortDropdownExpanded = !this.sortDropdownExpanded; + }} + > + {this.renderRadioButton(state.sortField == sortOption)} + {sortOption.localizedName} + + ); + } + + private renderRadioButton(checked = false){ + if (checked){ + return + } + else{ + return + } + } + render() { return ( @@ -39,6 +67,23 @@ export class DnnRmActionsBar { + + this.sortDropdownExpanded = !this.sortDropdownExpanded} + > + + {state.localization.Sort} + + + + + {this.renderSortButton(sortField.itemName)} + {this.renderSortButton(sortField.createdOnDate)} + {this.renderSortButton(sortField.lastModifiedOnDate)} + {this.renderSortButton(sortField.size)} + + + this.changeLayout()} > diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.tsx index 99983873e38..148a9a8bd91 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.tsx @@ -1,6 +1,7 @@ import { Component, Element, Host, h, Prop, Listen } from '@stencil/core'; import state from '../../store/store'; import { ItemsClient } from "../../services/ItemsClient"; +import { Debounce } from '@dnncommunity/dnn-elements'; @Component({ tag: 'dnn-rm-files-pane', styleUrl: 'dnn-rm-files-pane.scss', @@ -8,8 +9,9 @@ import { ItemsClient } from "../../services/ItemsClient"; }) export class DnnRmFilesPane { - @Prop() preloadOffset: number = 1000; - + /** Defines how much more pixels to load under the fold. */ + @Prop() preloadOffset: number = 5000; + @Element() el: HTMLDnnRmFilesPaneElement; private readonly itemsClient: ItemsClient; @@ -47,6 +49,7 @@ export class DnnRmFilesPane { } } + @Debounce(50) loadMore() { if (state.currentItems.items.length >= state.currentItems.totalCount){ return; @@ -56,7 +59,9 @@ export class DnnRmFilesPane { this.itemsClient.search( state.currentItems.folder.folderId, state.itemsSearchTerm, - state.lastSearchRequestedPage + 1) + state.lastSearchRequestedPage + 1, + state.pageSize, + state.sortField) .then(data => { state.lastSearchRequestedPage += 1; state.currentItems = { @@ -69,11 +74,14 @@ export class DnnRmFilesPane { else{ this.itemsClient.getFolderContent( state.currentItems.folder.folderId, - state.currentItems.items.length) + state.currentItems.items.length, + state.pageSize, + state.sortField) .then(data => state.currentItems = { ...state.currentItems, items: [...state.currentItems.items, ...data.items], - }); + }) + .catch(() => {}); // On purpose, we want to ignore aborted requests. } } diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.tsx index 07b1e444cef..fbb9fc0e401 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.tsx @@ -60,7 +60,11 @@ export class DnnRmFolderListItem { }; private handleFolderClicked(): void { - this.itemsClient.getFolderContent(Number.parseInt(this.folder.data.key)) + this.itemsClient.getFolderContent( + Number.parseInt(this.folder.data.key), + 0, + state.pageSize, + state.sortField) .then(data => state.currentItems = data) .catch(error => console.error(error)); } diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list/dnn-rm-folder-list.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list/dnn-rm-folder-list.tsx index 6ff102b7f2f..b88c666f663 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list/dnn-rm-folder-list.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list/dnn-rm-folder-list.tsx @@ -26,7 +26,11 @@ export class DnnRmFolderList { .then(data => { state.rootFolders = data; - this.itemsClient.getFolderContent(Number.parseInt(data.Tree.children[0].data.key)) + this.itemsClient.getFolderContent( + Number.parseInt(data.Tree.children[0].data.key), + 0, + state.pageSize, + state.sortField) .then(data => state.currentItems = data) .catch(error => console.error(error)); }) diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-top-bar/dnn-rm-top-bar.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-top-bar/dnn-rm-top-bar.tsx index 7e2e0cbfc82..2ce864bef82 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-top-bar/dnn-rm-top-bar.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-top-bar/dnn-rm-top-bar.tsx @@ -17,7 +17,11 @@ export class DnnRmTopBar { private handleSearchChanged(e: CustomEvent): void { if (e.detail != ""){ state.itemsSearchTerm = e.detail; - this.itemsClient.search(state.currentItems.folder.folderId, e.detail, 0) + this.itemsClient.search( + state.currentItems.folder.folderId, e.detail, + 0, + state.pageSize, + state.sortField) .then(data =>{ state.currentItems = { ...state.currentItems, @@ -30,7 +34,11 @@ export class DnnRmTopBar { } else { - this.itemsClient.getFolderContent(state.currentItems.folder.folderId, 0) + this.itemsClient.getFolderContent( + state.currentItems.folder.folderId, + 0, + state.pageSize, + state.sortField) .then(data => { state.lastSearchRequestedPage = 1; state.itemsSearchTerm = undefined; diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/enums/SortField.ts b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/enums/SortField.ts new file mode 100644 index 00000000000..635092586bd --- /dev/null +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/enums/SortField.ts @@ -0,0 +1,30 @@ +import state from "../store/store" +export class SortField{ + readonly itemName: SortFieldInfo; + readonly lastModifiedOnDate: SortFieldInfo; + readonly size: SortFieldInfo; + readonly parentFolder: SortFieldInfo; + readonly createdOnDate: SortFieldInfo; + + constructor(){ + this.itemName = new SortFieldInfo("ItemName"); + this.lastModifiedOnDate = new SortFieldInfo("LastModifiedOnDate"); + this.size = new SortFieldInfo("Size"); + this.parentFolder = new SortFieldInfo("ParentFolder"); + this.createdOnDate = new SortFieldInfo("CreatedOnDate"); + } +} + +export class SortFieldInfo{ + readonly sortKey: string; + + get localizedName(){ + return state.localization[`SortField_${this.sortKey}`]; + } + + constructor(sortKey: string){ + this.sortKey = sortKey; + } +} + +export const sortField = new SortField(); \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/ItemsClient.ts b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/ItemsClient.ts index f2406ccaf2b..aedcc54a030 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/ItemsClient.ts +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/ItemsClient.ts @@ -1,4 +1,5 @@ import { DnnServicesFramework } from "@dnncommunity/dnn-elements"; +import { SortFieldInfo } from "../enums/SortField"; export class ItemsClient{ private sf: DnnServicesFramework; @@ -26,10 +27,10 @@ export class ItemsClient{ folderId: number, startIndex = 0, numItems = 20, - sorting: "ItemName" | "LastModifiedOnDate" | "Size" | "ParentFolder" | "CreatedOnDate" = "ItemName", + sorting: SortFieldInfo = new SortFieldInfo("ItemName"), groupId = -1){ return new Promise((resolve, reject) => { - const url = `${this.requestUrl}GetFolderContent?folderId=${folderId}&startIndex=${startIndex}&numItems=${numItems}&sorting=${sorting}`; + const url = `${this.requestUrl}GetFolderContent?folderId=${folderId}&startIndex=${startIndex}&numItems=${numItems}&sorting=${sorting.sortKey}`; const headers = this.sf.getModuleHeaders(); headers.append("groupId", groupId.toString()); this.abortController?.abort(); @@ -73,12 +74,12 @@ export class ItemsClient{ search: string, pageIndex: number, pageSize = 20, - sorting: "ItemName" | "LastModifiedOnDate" | "Size" | "ParentFolder" | "CreatedOnDate" = "ItemName", + sorting: SortFieldInfo = new SortFieldInfo("ItemName"), culture = "", groupId = -1) { return new Promise((resolve, reject) => { - const url = `${this.requestUrl}Search?folderId=${folderId}&search=${search}&pageIndex=${pageIndex}&pageSize=${pageSize}&sorting=${sorting}&culture=${culture}`; + const url = `${this.requestUrl}Search?folderId=${folderId}&search=${search}&pageIndex=${pageIndex}&pageSize=${pageSize}&sorting=${sorting.sortKey}&culture=${culture}`; const headers = this.sf.getModuleHeaders(); headers.append("groupId", groupId.toString()); this.abortController?.abort(); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/LocalizationClient.ts b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/LocalizationClient.ts index 0990b818142..70c21dbbd22 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/LocalizationClient.ts +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/services/LocalizationClient.ts @@ -111,4 +111,10 @@ export interface LocalizedStrings { RemoveFolderTypeDialogHeader: String; MoveItem: String; NewLocation: String; + SortField_ItemName: String; + SortField_LastModifiedOnDate: String; + SortField_Size: String; + SortField_ParentFolder: String; + SortField_CreatedOnDate: String; + Sort: String; }; \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/store/store.ts b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/store/store.ts index ec8f957cad6..115e0993899 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/store/store.ts +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/store/store.ts @@ -1,4 +1,5 @@ import { createStore } from "@stencil/store"; +import { SortFieldInfo } from "../enums/SortField"; import { GetFoldersResponse } from "../services/InternalServicesClient"; import { GetFolderContentResponse } from "../services/ItemsClient"; import { LocalizedStrings } from "../services/LocalizationClient"; @@ -12,10 +13,11 @@ const { state } = createStore<{ itemsSearchTerm?: string; pageSize: number; lastSearchRequestedPage: number; + sortField?: SortFieldInfo; }>({ moduleId: -1, layout: "list", - pageSize: 20, + pageSize: 50, lastSearchRequestedPage: 1, });