Skip to content

Commit

Permalink
feat: display the children in a folder for a file list (#3339)
Browse files Browse the repository at this point in the history
* Update the dependencies

* Render children files as an unordered list

* Add styling and display css for the children

* Add classes and event listeners for display and navigation

* Use file list in nesting and add styling

Fixes for disambiguation and adds version bump

* Refactor breadcrumb handling in file list component for improved navigation

* Remove units for zero lengths
  • Loading branch information
musale authored Nov 18, 2024
1 parent e2edc88 commit 1afd741
Show file tree
Hide file tree
Showing 16 changed files with 114 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"stylelint.packageManager": "yarn",
"stylelint.snippet": ["css", "less", "postcss", "scss"],
"stylelint.validate": ["css", "less", "postcss", "scss"],
"cSpell.words": ["mailenabledsecurity"],
"cSpell.words": ["mailenabledsecurity", "noreferrer"],
"liveServer.settings.root": "storybook-static",
"liveServer.settings.port": 6006
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ $show-more-button-border-bottom-left-radius: var(
);
$progress-ring-size: var(--progress-ring-size, 24px);

@mixin nested-file-list($margin: 0) {
margin-inline-start: calc(#{$margin} * 2);
}

:host {
font-size: $font-size;

Expand Down Expand Up @@ -58,6 +62,25 @@ $progress-ring-size: var(--progress-ring-size, 24px);
flex-direction: column;
list-style: none;

.file-list-children {
&-show {
display: block;
@include nested-file-list(16px);

ul {
list-style: none;

li {
padding: 8px 0;
}
}
}

&-hide {
display: none;
}
}

.file-item {
cursor: pointer;
border-radius: var(--file-border-radius);
Expand All @@ -77,6 +100,10 @@ $progress-ring-size: var(--progress-ring-size, 24px);
--file-border-radius: 2px;
--file-background-color: var(--file-item-background-color, var(--neutral-layer-1));
}

.file-list-children {
background-color: beige;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
ProviderState,
mgtHtml,
MgtTemplatedTaskComponent,
registerComponent
registerComponent,
customElementHelper
} from '@microsoft/mgt-element';
import { DriveItem, SharedInsight } from '@microsoft/microsoft-graph-types';
import { html, TemplateResult } from 'lit';
Expand Down Expand Up @@ -516,6 +517,7 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
class="file-list"
>
<li
id="file-list-item-${this.files[0].id}"
tabindex="0"
class="file-item"
@keydown="${this.onFileListKeyDown}"
Expand All @@ -528,6 +530,7 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
f => f.id,
f => html`
<li
id="file-list-item-${f.id}"
class="file-item"
@keydown="${this.onFileListKeyDown}"
@click=${(e: UIEvent) => this.handleItemSelect(f, e)}>
Expand Down Expand Up @@ -587,7 +590,7 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
: null;

return html`
<div class="shared_insight_file" @click=${(e: MouseEvent) => this.handleFileClick(file, e)} tabindex="0">
<div class="shared_insight_file" @click=${(e: MouseEvent) => this.handleSharedInsightClick(file, e)} tabindex="0">
<div class="shared_insight_file__icon">
<img alt="${file.resourceVisualization.title}" src=${getFileTypeIconUri(
file.resourceVisualization.type,
Expand Down Expand Up @@ -665,7 +668,13 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
* @param event
*/
private readonly onFileListKeyDown = (event: KeyboardEvent): void => {
const fileList = this.renderRoot.querySelector('.file-list');
const target = event.target as HTMLElement;
let fileList: HTMLElement;
if (!target.classList) {
fileList = this.renderRoot.querySelector('.file-list-children');
} else {
fileList = this.renderRoot.querySelector('.file-list');
}
let focusedItem: HTMLElement;

if (!fileList?.children.length) {
Expand Down Expand Up @@ -822,6 +831,18 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
this.files = files;
}
}
for (const file of this.files) {
if (file?.folder?.childCount > 0) {
// expand the file with children
const driveId = file?.parentReference?.driveId;
const itemId = file?.id;
const iterator = await getDriveFilesByIdIterator(graph, driveId, itemId, 5);
if (iterator) {
const children = [...iterator.value];
file.children = children;
}
}
}
}

/**
Expand Down Expand Up @@ -894,15 +915,52 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
this.requestUpdate();
}

private readonly handleFileClick = (file: DriveItem | SharedInsight, e?: MouseEvent) => {
if (e && isSharedInsight(file) && file.resourceReference?.webUrl && !this.disableOpenOnClick) {
private readonly handleSharedInsightClick = (file: SharedInsight, e?: MouseEvent) => {
if (file.resourceReference?.webUrl && !this.disableOpenOnClick) {
e.preventDefault();
window.open(file.resourceReference.webUrl, '_blank', 'noreferrer');
} else if (!isSharedInsight(file) && file?.webUrl && !this.disableOpenOnClick) {
}
};

private readonly handleFileClick = (file: DriveItem) => {
const hasChildFolders = file?.folder?.childCount > 0 && file?.children;
// the item has child folders, on click should get the child folders and render them
if (hasChildFolders) {
this.showChildren(file.id);
return;
}

if (file?.webUrl && !this.disableOpenOnClick) {
window.open(file.webUrl, '_blank', 'noreferrer');
}
};

private readonly showChildren = (fileId: string) => {
const itemDOM = this.renderRoot.querySelector(`#file-list-item-${fileId}`);
this.renderChildren(fileId, itemDOM);
};

private readonly renderChildren = (itemId: string, itemDOM: Element) => {
const fileListName = customElementHelper.isDisambiguated
? `${customElementHelper.prefix}-file-list`
: 'mgt-file-list';
const childrenContainer = this.renderRoot.querySelector(`#file-list-children-${itemId}`);
if (!childrenContainer) {
const fl = document.createElement(fileListName);
fl.setAttribute('item-id', itemId);
fl.setAttribute('id', `file-list-children-${itemId}`);
fl.setAttribute('class', 'file-list-children-show');
itemDOM.after(fl);
} else {
// toggle to show/hide the children container
if (childrenContainer.classList.contains('file-list-children-hide')) {
childrenContainer.setAttribute('class', 'file-list-children-show');
} else {
childrenContainer.setAttribute('class', 'file-list-children-hide');
}
}
};

/**
* Get file extension string from file name
*
Expand Down
2 changes: 1 addition & 1 deletion packages/mgt-element/src/utils/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
// THIS FILE IS AUTO GENERATED
// ANY CHANGES WILL BE LOST DURING BUILD

export const PACKAGE_VERSION = '4.2.4';
export const PACKAGE_VERSION = '4.3.0';
64 changes: 21 additions & 43 deletions stories/components/fileList/fileList.html.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,60 +102,38 @@ export const openFolderBreadcrumbs = () => html`
<ul class="breadcrumb" id="nav">
<li><a id="home">Files</a></li>
</ul>
<mgt-file-list></mgt-file-list>
<mgt-file-list id="parent-file-list"></mgt-file-list>
<script type="module">
const fileList = document.querySelector('mgt-file-list');
const fileList = document.getElementById('parent-file-list');
const nav = document.getElementById('nav');
const home = document.getElementById('home');
let homeListId;
if (fileList.itemId) {
homeListId = fileList.itemId;
} else {
homeListId = null;
}
// handle default file list menu item
home.addEventListener('click', e => {
fileList.itemId = homeListId;
removeListItems(1);
});
// handle create and remove menu items
fileList.addEventListener('itemClick', e => {
if (e.detail && e.detail.folder) {
const id = e.detail.id;
const name = e.detail.name;
// render new file list
fileList.itemId = id;
// create breadcrumb menu item
const li = document.createElement('li');
const a = document.createElement('a');
li.setAttribute('id', id);
a.appendChild(document.createTextNode(name));
li.appendChild(a);
nav.appendChild(li);
// remove breadcrumb menu items and render file list based on clicked item
a.addEventListener('click', e => {
const nodes = Array.from(nav.children);
const index = nodes.indexOf(li);
if (e.target) {
removeListItems(index + 1);
fileList.itemId = li.id;
const breadcrumbId = "breadcrumb-"+ id;
// check if it is set
const breadcrumbSet = document.getElementById(breadcrumbId);
if (!breadcrumbSet) {
// create breadcrumb menu item
const li = document.createElement('li');
const a = document.createElement('a');
li.setAttribute('id', breadcrumbId);
a.appendChild(document.createTextNode(name));
li.appendChild(a);
if (nav.children.length > 1){
const firstBreadcrumb = nav.children[0];
nav.replaceChildren(firstBreadcrumb);
}
});
nav.appendChild(li);
} else {
breadcrumbSet.remove();
}
}
});
// remove li of ul where index is larger than n
function removeListItems(n) {
while (nav.getElementsByTagName('li').length > n) {
nav.removeChild(nav.lastChild);
}
}
</script>
`;

0 comments on commit 1afd741

Please sign in to comment.