diff options
author | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2023-07-11 15:06:03 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-11 15:06:03 +0200 |
commit | 2cf8d6d9652a55f81c6800f2e69b71597736c56c (patch) | |
tree | 3e48463d8ebc3c01961243e8e6b1fc10a60133b7 /apps | |
parent | 5c6ed30369f5c4edcf46e5e882c6096a7e3cd01e (diff) | |
parent | 74763e875737ea2bb0775194544a809041a2e7d6 (diff) | |
download | nextcloud-server-2cf8d6d9652a55f81c6800f2e69b71597736c56c.tar.gz nextcloud-server-2cf8d6d9652a55f81c6800f2e69b71597736c56c.zip |
Merge pull request #39196 from nextcloud/feat/f2v/sharing
Diffstat (limited to 'apps')
41 files changed, 2088 insertions, 1299 deletions
diff --git a/apps/files/css/files.css b/apps/files/css/files.css index b91dcf94b81..b4b64abdef9 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -1 +1 @@ -.actions{padding:3px;height:100%;display:inline-block;float:left}.actions input,.actions button,.actions .button{margin:0;float:left}.actions .button a{color:#555}.actions .button a:hover,.actions .button a:focus{background-color:var(--color-background-hover)}.actions .button a:active{background-color:var(--color-primary-element-light)}.actions.creatable{position:relative;display:flex;flex:1 1}.actions.creatable .button:not(:last-child){margin-right:3px}.actions.hidden{display:none}#trash{margin-right:8px;float:right;z-index:1010;padding:10px;font-weight:normal}.newFileMenu .error,.newFileMenu .error+.icon-confirm,.files-fileList .error{color:var(--color-error);border-color:var(--color-error)}.files-filestable{position:relative;width:100%;min-width:250px;display:block;flex-direction:column}.emptycontent:not(.hidden)~.files-filestable{display:none}.files-filestable thead{position:-webkit-sticky;position:sticky;top:44px;z-index:60;display:block;background-color:var(--color-main-background-translucent)}.files-filestable tbody{display:table;width:100%}.files-filestable tbody tr[data-permissions="0"],.files-filestable tbody tr[data-permissions="16"]{background-color:var(--color-background-dark)}.files-filestable tbody tr[data-permissions="0"] td.filename .nametext .innernametext,.files-filestable tbody tr[data-permissions="16"] td.filename .nametext .innernametext{color:var(--color-text-maxcontrast)}.files-filestable tbody tr[data-e2eencrypted=true] .selection{pointer-events:none}.files-filestable.hidden{display:none}.app-files #app-content>.viewcontainer{min-height:0%;width:100%}.app-files #app-content{width:calc(100% - 300px);overflow-anchor:none}.file-drag,.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:var(--color-primary-element-light) !important}.app-files #app-content.dir-drop{background-color:var(--color-main-background) !important}.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:rgba(0,0,0,0) !important}.app-files #app-content.dir-drop .files-filestable tbody tr.dropping-to-dir{background-color:var(--color-primary-element-light) !important}.nav-icon-files{background-image:var(--icon-folder-dark)}.nav-icon-recent{background-image:var(--icon-recent-dark)}.nav-icon-favorites{background-image:var(--icon-starred-dark)}.nav-icon-sharingin,.nav-icon-sharingout,.nav-icon-pendingshares,.nav-icon-shareoverview{background-image:var(--icon-share-dark)}.nav-icon-sharinglinks{background-image:var(--icon-public-dark)}.nav-icon-extstoragemounts{background-image:var(--icon-external-dark)}.nav-icon-trashbin{background-image:var(--icon-delete-dark)}.nav-icon-trashbin-starred{background-image:var(--icon-delete-#ff0000)}.nav-icon-deletedshares{background-image:var(--icon-unshare-dark)}.nav-icon-favorites-starred{background-image:var(--icon-starred-yellow)}#app-navigation .nav-files a.nav-icon-files{width:auto}#app-navigation .nav-files a.new{width:40px;height:32px;padding:0 10px;margin:0;cursor:pointer}#app-navigation .nav-files a.new.hidden{display:none}#app-navigation .nav-files a.new.disabled{opacity:.3}.files-filestable tbody tr{height:51px}.files-filestable tbody tr:hover,.files-filestable tbody tr:focus,.files-filestable tbody .name:focus,.files-filestable tbody tr:hover .filename form,table tr.mouseOver td{background-color:var(--color-background-hover)}.files-filestable tbody tr:active,.files-filestable tbody tr.highlighted,.files-filestable tbody tr.highlighted .name:focus,.files-filestable tbody tr.selected,.files-filestable tbody tr.searchresult{background-color:var(--color-primary-element-light)}tbody a{color:var(--color-main-text)}span.conflict-path,span.extension,span.uploading,td.date{color:var(--color-text-maxcontrast)}span.conflict-path,span.extension{-webkit-transition:opacity 300ms;-moz-transition:opacity 300ms;-o-transition:opacity 300ms;transition:opacity 300ms;vertical-align:top}tr:hover span.conflict-path,tr:focus span.conflict-path,tr:hover span.extension,tr:focus span.extension{opacity:1;color:var(--color-text-maxcontrast)}table th,table th a{color:var(--color-text-maxcontrast)}table.multiselect th a{color:var(--color-main-text)}table th .columntitle{display:block;padding:15px;height:50px;box-sizing:border-box;-moz-box-sizing:border-box;vertical-align:middle}table th .columntitle:focus-visible{border-radius:2px}table.multiselect th .columntitle{display:inline-block;margin-right:-20px}table th .columntitle.name{padding-left:0;margin-left:44px}table.multiselect th .columntitle.name{margin-left:0}table th .sort-indicator{width:10px;height:8px;margin-left:5px;display:inline-block;vertical-align:text-bottom;opacity:.3}.sort-indicator.hidden,.multiselect .sort-indicator,table.multiselect th:hover .sort-indicator.hidden,table.multiselect th:focus .sort-indicator.hidden{visibility:hidden}.multiselect .sort,.multiselect .sort span{cursor:default}table th:hover .sort-indicator.hidden,table th:focus .sort-indicator.hidden{visibility:visible}table th,table td{border-bottom:1px solid var(--color-border);text-align:left;font-weight:normal}table td{padding:0 15px;font-style:normal;background-position:8px center;background-repeat:no-repeat}table th.column-name{position:relative;width:9999px;padding:0}.column-name-container{position:relative;height:50px}table th.column-selection{padding-top:2px}table th.column-size,table td.filesize{text-align:right}table th.column-mtime,table td.date,table th.column-last,table td.column-last{-moz-box-sizing:border-box;box-sizing:border-box;position:relative;min-width:130px}#app-content-recent,#app-content-favorites,#app-content-shareoverview,#app-content-sharingout,#app-content-sharingin,#app-content-sharinglinks,#app-content-deletedshares,#app-content-pendingshares{margin-top:22px}#app-content-recent thead,#app-content-favorites thead,#app-content-shareoverview thead,#app-content-sharingout thead,#app-content-sharingin thead,#app-content-sharinglinks thead,#app-content-deletedshares thead,#app-content-pendingshares thead{top:0}table.multiselect thead th{background-color:var(--color-main-background-translucent);font-weight:bold}#app-content.with-app-sidebar table.multiselect thead{margin-right:27%}table.multiselect .column-name{position:relative;width:9999px}table.multiselect .column-mtime>a{display:none}table td.selection,table th.selection,table td.fileaction{width:32px;text-align:center}table td.filename a.name,table td.filename p.name{display:flex;position:relative;-moz-box-sizing:border-box;box-sizing:border-box;height:50px;line-height:50px;padding:0}table td.filename .thumbnail-wrapper{width:0;min-width:50px;max-width:50px;height:50px}table td.filename .thumbnail-wrapper.icon-loading-small:after{z-index:10}table td.filename .thumbnail-wrapper.icon-loading-small .thumbnail{opacity:.2}table td.filename .thumbnail{display:inline-block;width:32px;height:32px;background-size:contain;background-position:center;background-repeat:no-repeat;margin-left:9px;margin-top:9px;border-radius:var(--border-radius);cursor:pointer;position:absolute;z-index:4}table td.filename p.name .thumbnail{cursor:default}table tr[data-has-preview=true] .thumbnail{border:1px solid var(--color-border)}table:not(.view-grid) td.filename input.filename{width:70% !important;margin-left:48px !important;cursor:text}table td.filename form{margin-top:-40px;position:relative;top:-6px}table td.filename a,table td.login,table td.logout,table td.download,table td.upload,table td.create,table td.delete{padding:3px 8px 8px 3px}table td.filename .nametext,.modified,.column-last>span:first-child{float:left;padding:15px 0}.modified,.column-last>span:first-child{position:relative;overflow:hidden;text-overflow:ellipsis;width:110px}table td.filename{max-width:0}table td.filename .nametext{width:0;flex-grow:1;display:flex;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;height:100%;z-index:10;padding:0 20px 0 0}table td.filename .system-tags{--min-size: 32px;display:flex;justify-content:center;align-items:center;min-width:calc(var(--min-size)*2);max-width:300px}table td.filename .system-tags .system-tags__tag{padding:5px 10px;border:1px solid;border-radius:var(--border-radius-pill);border-color:var(--color-border);color:var(--color-text-maxcontrast);height:var(--min-size);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:22px;text-align:center}table td.filename .system-tags .system-tags__tag--more{overflow:visible;text-overflow:initial}table td.filename .system-tags .system-tags__tag+.system-tags__tag{margin-left:5px}.hide-hidden-files .files-filestable .files-fileList tr.hidden-file,.hide-hidden-files .files-filestable .files-fileList tr.hidden-file.dragging{display:none !important}.files-fileList tr.animate-opacity{-webkit-transition:opacity 250ms;-moz-transition:opacity 250ms;-o-transition:opacity 250ms;transition:opacity 250ms}.files-fileList tr.dragging{opacity:.2}table td.filename .nametext .innernametext{text-overflow:ellipsis;overflow:hidden;position:relative;vertical-align:top}table td.filename .uploadtext{position:absolute;font-weight:normal;margin-left:50px;left:0;bottom:0;height:20px;padding:0 4px;padding-left:1px;font-size:11px;line-height:22px;color:var(--color-text-maxcontrast);text-overflow:ellipsis;white-space:nowrap}table td.selection{padding:0}.files-fileList tr td.selection>.selectCheckBox+label:before{opacity:.3;margin-right:0}.files-fileList tr:hover td.selection>.selectCheckBox+label:before,.files-fileList tr:focus td.selection>.selectCheckBox+label:before,.files-fileList tr td.selection>.selectCheckBox:checked+label:before,.files-fileList tr.selected td.selection>.selectCheckBox+label:before{opacity:1}.files-fileList tr.halfselected td.selection>.selectCheckBox+label:before{opacity:.5}.files-fileList tr td.selection>.selectCheckBox+label,.select-all+label{padding:16px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill);outline:none !important;border:2px solid var(--color-primary-element) !important;padding:14px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{outline-offset:0px}.files-fileList tr td.filename{position:relative;width:100%;padding-left:0;padding-right:0;-webkit-transition:background-image 500ms;-moz-transition:background-image 500ms;-o-transition:background-image 500ms;transition:background-image 500ms}.files-fileList tr td.filename a.name label,.files-fileList tr td.filename p.name label{position:absolute;width:80%;height:50px}.files-fileList tr td.filename .favorite{display:inline-block;float:left}.files-fileList tr td.filename .favorite-mark{position:absolute;display:block;top:-8px;right:-8px;line-height:100%;text-align:center}.files-fileList tr td.filename .favorite-mark.permanent{background-color:var(--color-main-background);mask:var(--icon-star-rounded-white) no-repeat;mask-size:22px 22px;width:22px;height:22px;display:flex;align-content:center;justify-content:center}.files-fileList tr:hover td.filename .favorite-mark.permanent{background-color:var(--color-background-hover)}#uploadsize-message,#delete-confirm{display:none}.fileactions{z-index:50}.busy .fileactions,.busy .action{visibility:hidden}.bubble,#app-navigation .app-navigation-entry-menu{min-width:100px}.files-fileList .icon-loading-small{opacity:1 !important;display:inline !important}.files-fileList .action.action-share-notification span,.files-fileList a.name{cursor:default !important}.files-fileList a.name.disabled *{cursor:default}.files-fileList a.name.disabled a,.files-fileList a.name.disabled a *{cursor:pointer}.files-fileList a.name.disabled:focus{background:none}a.action>img{height:16px;width:16px;vertical-align:text-bottom}a.action.action-editlocally img.icon{filter:var(--background-invert-if-dark)}.selectedActions{position:relative;display:inline-block;vertical-align:middle}.selectedActions.hidden{display:none}.selectedActions a{display:inline;line-height:50px;padding:16px 5px}.selectedActions a.hidden{display:none}.selectedActions a img{position:relative;vertical-align:text-bottom;margin-bottom:-1px}.selectedActions .actions-selected .icon-more{margin-top:-3px}.files-fileList td a a.action{display:inline;padding:17px 8px;line-height:50px;opacity:.3}.files-fileList td a a.action.action-share{padding:17px 14px}.files-fileList td a a.action.action-share.permanent:not(.shared-style) .icon-shared+span{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}.files-fileList td a a.action.action-share .avatar{display:inline-block;vertical-align:middle}.files-fileList td a a.action.action-menu{padding-top:17px;padding-bottom:17px;padding-left:14px;padding-right:14px}.files-fileList td a a.action.no-permission:hover,.files-fileList td a a.action.no-permission:focus{opacity:.3}.files-fileList td a a.action.disabled:hover,.files-fileList td a a.action.disabled:focus,.files-fileList td a a.action.disabled img{opacity:.3}.files-fileList td a a.action.disabled.action-download{opacity:.7}.files-fileList td a a.action.disabled.action-download:hover,.files-fileList td a a.action.disabled.action-download:focus{opacity:.7}.files-fileList td a a.action:hover,.files-fileList td a a.action:focus{opacity:1}.files-fileList td a a.action:focus{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill)}.files-fileList td a .fileActionsMenu a.action,.files-fileList td a a.action.action-share.shared-style{opacity:.7}.files-fileList td a .fileActionsMenu .action.permanent{opacity:1}.files-fileList .action.action-share.permanent.shared-style span:not(.icon){display:inline-block;max-width:70px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;margin-left:6px}.files-fileList .remoteAddress .userDomain{margin-left:0 !important}.files-fileList .favorite-mark.permanent{opacity:1}.files-fileList .fileActionsMenu a.action:hover,.files-fileList .fileActionsMenu a.action:focus,.files-fileList a.action.action-share.shared-style:hover,.files-fileList a.action.action-share.shared-style:focus{opacity:1}.files-fileList tr a.action.disabled{background:none}.selectedActions a.download.disabled,.files-fileList tr a.action.action-download.disabled{color:#000}.files-fileList tr:hover a.action.disabled:hover *{cursor:default}.summary{color:var(--color-text-maxcontrast);height:330px}.files-filestable .summary .filesummary{width:100%;padding-left:101px}#body-public .summary{height:180px}.summary:hover,.summary:focus,.summary,table tr.summary td{background-color:rgba(0,0,0,0)}.summary td{border-bottom:none;vertical-align:top;padding-top:20px}.summary td:first-child{padding:0}.hiddeninfo{white-space:pre-line}table.dragshadow{width:auto;z-index:2000}table.dragshadow td.filename{padding-left:60px;padding-right:16px;height:36px;max-width:unset}table.dragshadow td.size{padding-right:8px}.mask{z-index:50;position:absolute;top:0;left:0;right:0;bottom:0;background-color:var(--color-main-background);background-repeat:no-repeat no-repeat;background-position:50%;opacity:.7;transition:opacity 100ms;-moz-transition:opacity 100ms;-o-transition:opacity 100ms;-ms-transition:opacity 100ms;-webkit-transition:opacity 100ms}.mask.transparent{opacity:0}.newFileMenu{font-weight:300;top:100%;left:-48px !important;margin-top:4px;min-width:100px;z-index:1001}.newFileMenu::after{left:61px !important}.files-controls{box-sizing:border-box;position:-webkit-sticky;position:sticky;height:50px;padding:0;margin:0;background-color:var(--color-main-background-translucent);z-index:62;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;top:0;padding-left:50px}.files-controls .actions>div>.button,.files-controls .actions>div button,.files-controls .actions>.button,.files-controls .actions button{box-sizing:border-box;display:inline-block;display:flex;height:44px;width:44px;padding:9px;align-items:center;justify-content:center}.files-controls .actions>div .button.hidden,.files-controls .actions .button.hidden{display:none}.viewer-mode #app-navigation+#app-content .files-controls{left:0}.files-filestable .filename .action .icon,.files-filestable .selectedActions a .icon,.files-filestable .filename .favorite-mark .icon,.files-controls .actions .button .icon{display:inline-block;vertical-align:middle;background-size:16px 16px}.files-filestable .filename .favorite-mark .icon-star{background-image:none}.files-filestable .filename .favorite-mark .icon-starred{background-image:var(--icon-starred-yellow) !important}.files-filestable .filename .action .icon.hidden,.files-filestable .selectedActions a .icon.hidden,.files-controls .actions .button .icon.hidden{display:none}.files-filestable .filename .action .icon.loading,.files-filestable .selectedActions a .icon.loading,.files-controls .actions .button .icon.loading{width:15px;height:15px}.app-files .actions .button.new{position:relative}.breadcrumb{align-items:center}.breadcrumb .icon-home{border-radius:var(--border-radius)}.breadcrumb .canDrop>a,.files-filestable tbody tr.canDrop{background-color:rgba(0,130,201,.3)}.dropzone-background{background-color:rgba(0,130,201,.3)}.dropzone-background :hover{box-shadow:none !important}.notCreatable{margin-left:12px;margin-right:44px;margin-top:12px;color:var(--color-main-text);overflow:auto;min-width:160px;height:54px}.notCreatable:not(.hidden){display:flex}.notCreatable .icon-alert-outline{top:-15px;position:relative;margin-right:4px}.quota-navigation-item{margin:0 !important;border:none;border-radius:0;background-color:rgba(0,0,0,0);z-index:1;height:44px;display:flex !important;flex-direction:column}.quota-navigation-item__text{height:30px}.quota-navigation-item[href="#"],.quota-navigation-item[href="#"] *{cursor:default !important}.quota-navigation-item__container{height:5px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) thead tr{display:block;border-bottom:1px solid var(--color-border);background-color:var(--color-main-background-translucent)}.files-filestable.view-grid:not(.hidden) thead tr th{width:auto;border:none}.files-filestable.view-grid:not(.hidden) tbody{display:grid;grid-template-columns:repeat(auto-fill, 160px);justify-content:space-around;row-gap:15px;margin:15px 0}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden){display:block;position:relative;height:190px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted{background-color:rgba(0,0,0,0)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .fileactions{background-color:var(--color-background-hover)}.files-filestable.view-grid:not(.hidden) tbody td{display:inline;border-bottom:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper{min-width:0;max-width:none;position:absolute;width:160px;height:160px;padding:14px;top:0;left:0;z-index:-1}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail{width:calc(100% - 2 * 14px);height:calc(100% - 2 * 14px);background-size:contain;margin:0;border-radius:var(--border-radius);background-repeat:no-repeat;background-position:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail .favorite-mark{left:auto;top:-11px;right:-11px}.files-filestable.view-grid:not(.hidden) tbody td.filename .uploadtext{width:100%;margin:0;top:0;bottom:auto;height:28px;padding-top:4px;padding-left:28px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name{height:100%;border-radius:var(--border-radius);overflow:hidden;cursor:pointer !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext{display:flex;height:44px;margin-top:146px;text-align:center;line-height:44px;padding:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{display:inline-block;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:before{content:"";flex:1;min-width:14px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:after{content:"";flex:1;min-width:44px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .extension{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .system-tags{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions{height:initial;margin-top:146px;display:flex;align-items:center;position:absolute;right:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action{padding:14px;width:44px;height:44px;display:flex;align-items:center;justify-content:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action:not(.action-menu){display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden .action-share img{padding:6px;border-radius:50%}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-restore-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-comment-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename form{padding:3px 14px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody td.filename form input.filename{width:100%;margin-left:0;cursor:text}.files-filestable.view-grid:not(.hidden) tbody td.filesize,.files-filestable.view-grid:not(.hidden) tbody td.date{display:none}.files-filestable.view-grid:not(.hidden) tbody td.selection,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark{position:absolute;top:-8px;left:-8px;display:flex;z-index:10}.files-filestable.view-grid:not(.hidden) tbody td.selection label,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label{width:44px;height:44px;display:inline-flex;padding:14px}.files-filestable.view-grid:not(.hidden) tbody td.selection label::before,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label::before{margin:0;width:14px;height:14px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:0;width:150px;margin:0 5px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu .menuitem span:not(.icon){overflow:hidden;text-overflow:ellipsis}.files-filestable.view-grid:not(.hidden) tr.hidden-file td.filename .name .nametext .extension{display:block}.files-filestable.view-grid:not(.hidden) tfoot{display:grid}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden){display:inline-block;margin:0 auto;height:418px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td{padding-top:50px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td:first-child,.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td.date{display:none}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td .info{margin-left:0}#view-toggle{background-color:var(--color-main-background-translucent);border:none;margin:0;padding:22px;opacity:.5;float:right;right:var(--default-grid-baseline);top:var(--default-grid-baseline);z-index:100;position:sticky}#view-toggle:hover,#view-toggle:focus,#showgridview:focus+#view-toggle{opacity:1}#view-toggle:focus-visible,#showgridview:focus-visible+#view-toggle{box-shadow:inset 0 0 0 2px var(--color-primary-element) !important}#showgridview{position:fixed;top:0}#body-public .files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{max-width:124px}#body-public .files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:-80px}#body-public #view-toggle{position:absolute;right:0;top:0}#gallery-button{display:none}#tag_multiple_files_container{overflow:hidden;background-color:#fff;border-radius:3px;position:relative;display:flex;flex-wrap:wrap;margin-bottom:10px}#tag_multiple_files_container h3{width:100%;padding:0 18px}#tag_multiple_files_container .systemTagsInputFieldContainer{flex:1 1 80%;min-width:0;margin:0 12px}/*# sourceMappingURL=files.css.map */ +.actions{padding:3px;height:100%;display:inline-block;float:left}.actions input,.actions button,.actions .button{margin:0;float:left}.actions .button a{color:#555}.actions .button a:hover,.actions .button a:focus{background-color:var(--color-background-hover)}.actions .button a:active{background-color:var(--color-primary-element-light)}.actions.creatable{position:relative;display:flex;flex:1 1}.actions.creatable .button:not(:last-child){margin-right:3px}.actions.hidden{display:none}#trash{margin-right:8px;float:right;z-index:1010;padding:10px;font-weight:normal}.newFileMenu .error,.newFileMenu .error+.icon-confirm,.files-fileList .error{color:var(--color-error);border-color:var(--color-error)}.files-filestable{position:relative;width:100%;min-width:250px;display:block;flex-direction:column}.emptycontent:not(.hidden)~.files-filestable{display:none}.files-filestable thead{position:-webkit-sticky;position:sticky;top:44px;z-index:60;display:block;background-color:var(--color-main-background-translucent)}.files-filestable tbody{display:table;width:100%}.files-filestable tbody tr[data-permissions="0"],.files-filestable tbody tr[data-permissions="16"]{background-color:var(--color-background-dark)}.files-filestable tbody tr[data-permissions="0"] td.filename .nametext .innernametext,.files-filestable tbody tr[data-permissions="16"] td.filename .nametext .innernametext{color:var(--color-text-maxcontrast)}.files-filestable tbody tr[data-e2eencrypted=true] .selection{pointer-events:none}.files-filestable.hidden{display:none}.app-files #app-content>.viewcontainer{min-height:0%;width:100%}.app-files #app-content{width:calc(100% - 300px);overflow-anchor:none}.file-drag,.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:var(--color-primary-element-light) !important}.app-files #app-content.dir-drop{background-color:var(--color-main-background) !important}.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:rgba(0,0,0,0) !important}.app-files #app-content.dir-drop .files-filestable tbody tr.dropping-to-dir{background-color:var(--color-primary-element-light) !important}.nav-icon-files{background-image:var(--icon-folder-dark)}.nav-icon-recent{background-image:var(--icon-recent-dark)}.nav-icon-favorites{background-image:var(--icon-starred-dark)}.nav-icon-sharinginOld,.nav-icon-sharingoutOld,.nav-icon-pendingsharesOld,.nav-icon-shareoverviewOld{background-image:var(--icon-share-dark)}.nav-icon-sharinglinksOld{background-image:var(--icon-public-dark)}.nav-icon-extstoragemounts{background-image:var(--icon-external-dark)}.nav-icon-trashbin{background-image:var(--icon-delete-dark)}.nav-icon-trashbin-starred{background-image:var(--icon-delete-#ff0000)}.nav-icon-deletedsharesOld{background-image:var(--icon-unshare-dark)}.nav-icon-favorites-starred{background-image:var(--icon-starred-yellow)}#app-navigation .nav-files a.nav-icon-files{width:auto}#app-navigation .nav-files a.new{width:40px;height:32px;padding:0 10px;margin:0;cursor:pointer}#app-navigation .nav-files a.new.hidden{display:none}#app-navigation .nav-files a.new.disabled{opacity:.3}.files-filestable tbody tr{height:51px}.files-filestable tbody tr:hover,.files-filestable tbody tr:focus,.files-filestable tbody .name:focus,.files-filestable tbody tr:hover .filename form,table tr.mouseOver td{background-color:var(--color-background-hover)}.files-filestable tbody tr:active,.files-filestable tbody tr.highlighted,.files-filestable tbody tr.highlighted .name:focus,.files-filestable tbody tr.selected,.files-filestable tbody tr.searchresult{background-color:var(--color-primary-element-light)}tbody a{color:var(--color-main-text)}span.conflict-path,span.extension,span.uploading,td.date{color:var(--color-text-maxcontrast)}span.conflict-path,span.extension{-webkit-transition:opacity 300ms;-moz-transition:opacity 300ms;-o-transition:opacity 300ms;transition:opacity 300ms;vertical-align:top}tr:hover span.conflict-path,tr:focus span.conflict-path,tr:hover span.extension,tr:focus span.extension{opacity:1;color:var(--color-text-maxcontrast)}table th,table th a{color:var(--color-text-maxcontrast)}table.multiselect th a{color:var(--color-main-text)}table th .columntitle{display:block;padding:15px;height:50px;box-sizing:border-box;-moz-box-sizing:border-box;vertical-align:middle}table th .columntitle:focus-visible{border-radius:2px}table.multiselect th .columntitle{display:inline-block;margin-right:-20px}table th .columntitle.name{padding-left:0;margin-left:44px}table.multiselect th .columntitle.name{margin-left:0}table th .sort-indicator{width:10px;height:8px;margin-left:5px;display:inline-block;vertical-align:text-bottom;opacity:.3}.sort-indicator.hidden,.multiselect .sort-indicator,table.multiselect th:hover .sort-indicator.hidden,table.multiselect th:focus .sort-indicator.hidden{visibility:hidden}.multiselect .sort,.multiselect .sort span{cursor:default}table th:hover .sort-indicator.hidden,table th:focus .sort-indicator.hidden{visibility:visible}table th,table td{border-bottom:1px solid var(--color-border);text-align:left;font-weight:normal}table td{padding:0 15px;font-style:normal;background-position:8px center;background-repeat:no-repeat}table th.column-name{position:relative;width:9999px;padding:0}.column-name-container{position:relative;height:50px}table th.column-selection{padding-top:2px}table th.column-size,table td.filesize{text-align:right}table th.column-mtime,table td.date,table th.column-last,table td.column-last{-moz-box-sizing:border-box;box-sizing:border-box;position:relative;min-width:130px}#app-content-recent,#app-content-favorites,#app-content-shareoverview,#app-content-sharingout,#app-content-sharingin,#app-content-sharinglinks,#app-content-deletedshares,#app-content-pendingshares{margin-top:22px}#app-content-recent thead,#app-content-favorites thead,#app-content-shareoverview thead,#app-content-sharingout thead,#app-content-sharingin thead,#app-content-sharinglinks thead,#app-content-deletedshares thead,#app-content-pendingshares thead{top:0}table.multiselect thead th{background-color:var(--color-main-background-translucent);font-weight:bold}#app-content.with-app-sidebar table.multiselect thead{margin-right:27%}table.multiselect .column-name{position:relative;width:9999px}table.multiselect .column-mtime>a{display:none}table td.selection,table th.selection,table td.fileaction{width:32px;text-align:center}table td.filename a.name,table td.filename p.name{display:flex;position:relative;-moz-box-sizing:border-box;box-sizing:border-box;height:50px;line-height:50px;padding:0}table td.filename .thumbnail-wrapper{width:0;min-width:50px;max-width:50px;height:50px}table td.filename .thumbnail-wrapper.icon-loading-small:after{z-index:10}table td.filename .thumbnail-wrapper.icon-loading-small .thumbnail{opacity:.2}table td.filename .thumbnail{display:inline-block;width:32px;height:32px;background-size:contain;background-position:center;background-repeat:no-repeat;margin-left:9px;margin-top:9px;border-radius:var(--border-radius);cursor:pointer;position:absolute;z-index:4}table td.filename p.name .thumbnail{cursor:default}table tr[data-has-preview=true] .thumbnail{border:1px solid var(--color-border)}table:not(.view-grid) td.filename input.filename{width:70% !important;margin-left:48px !important;cursor:text}table td.filename form{margin-top:-40px;position:relative;top:-6px}table td.filename a,table td.login,table td.logout,table td.download,table td.upload,table td.create,table td.delete{padding:3px 8px 8px 3px}table td.filename .nametext,.modified,.column-last>span:first-child{float:left;padding:15px 0}.modified,.column-last>span:first-child{position:relative;overflow:hidden;text-overflow:ellipsis;width:110px}table td.filename{max-width:0}table td.filename .nametext{width:0;flex-grow:1;display:flex;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;height:100%;z-index:10;padding:0 20px 0 0}table td.filename .system-tags{--min-size: 32px;display:flex;justify-content:center;align-items:center;min-width:calc(var(--min-size)*2);max-width:300px}table td.filename .system-tags .system-tags__tag{padding:5px 10px;border:1px solid;border-radius:var(--border-radius-pill);border-color:var(--color-border);color:var(--color-text-maxcontrast);height:var(--min-size);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:22px;text-align:center}table td.filename .system-tags .system-tags__tag--more{overflow:visible;text-overflow:initial}table td.filename .system-tags .system-tags__tag+.system-tags__tag{margin-left:5px}.hide-hidden-files .files-filestable .files-fileList tr.hidden-file,.hide-hidden-files .files-filestable .files-fileList tr.hidden-file.dragging{display:none !important}.files-fileList tr.animate-opacity{-webkit-transition:opacity 250ms;-moz-transition:opacity 250ms;-o-transition:opacity 250ms;transition:opacity 250ms}.files-fileList tr.dragging{opacity:.2}table td.filename .nametext .innernametext{text-overflow:ellipsis;overflow:hidden;position:relative;vertical-align:top}table td.filename .uploadtext{position:absolute;font-weight:normal;margin-left:50px;left:0;bottom:0;height:20px;padding:0 4px;padding-left:1px;font-size:11px;line-height:22px;color:var(--color-text-maxcontrast);text-overflow:ellipsis;white-space:nowrap}table td.selection{padding:0}.files-fileList tr td.selection>.selectCheckBox+label:before{opacity:.3;margin-right:0}.files-fileList tr:hover td.selection>.selectCheckBox+label:before,.files-fileList tr:focus td.selection>.selectCheckBox+label:before,.files-fileList tr td.selection>.selectCheckBox:checked+label:before,.files-fileList tr.selected td.selection>.selectCheckBox+label:before{opacity:1}.files-fileList tr.halfselected td.selection>.selectCheckBox+label:before{opacity:.5}.files-fileList tr td.selection>.selectCheckBox+label,.select-all+label{padding:16px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill);outline:none !important;border:2px solid var(--color-primary-element) !important;padding:14px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{outline-offset:0px}.files-fileList tr td.filename{position:relative;width:100%;padding-left:0;padding-right:0;-webkit-transition:background-image 500ms;-moz-transition:background-image 500ms;-o-transition:background-image 500ms;transition:background-image 500ms}.files-fileList tr td.filename a.name label,.files-fileList tr td.filename p.name label{position:absolute;width:80%;height:50px}.files-fileList tr td.filename .favorite{display:inline-block;float:left}.files-fileList tr td.filename .favorite-mark{position:absolute;display:block;top:-8px;right:-8px;line-height:100%;text-align:center}.files-fileList tr td.filename .favorite-mark.permanent{background-color:var(--color-main-background);mask:var(--icon-star-rounded-white) no-repeat;mask-size:22px 22px;width:22px;height:22px;display:flex;align-content:center;justify-content:center}.files-fileList tr:hover td.filename .favorite-mark.permanent{background-color:var(--color-background-hover)}#uploadsize-message,#delete-confirm{display:none}.fileactions{z-index:50}.busy .fileactions,.busy .action{visibility:hidden}.bubble,#app-navigation .app-navigation-entry-menu{min-width:100px}.files-fileList .icon-loading-small{opacity:1 !important;display:inline !important}.files-fileList .action.action-share-notification span,.files-fileList a.name{cursor:default !important}.files-fileList a.name.disabled *{cursor:default}.files-fileList a.name.disabled a,.files-fileList a.name.disabled a *{cursor:pointer}.files-fileList a.name.disabled:focus{background:none}a.action>img{height:16px;width:16px;vertical-align:text-bottom}a.action.action-editlocally img.icon{filter:var(--background-invert-if-dark)}.selectedActions{position:relative;display:inline-block;vertical-align:middle}.selectedActions.hidden{display:none}.selectedActions a{display:inline;line-height:50px;padding:16px 5px}.selectedActions a.hidden{display:none}.selectedActions a img{position:relative;vertical-align:text-bottom;margin-bottom:-1px}.selectedActions .actions-selected .icon-more{margin-top:-3px}.files-fileList td a a.action{display:inline;padding:17px 8px;line-height:50px;opacity:.3}.files-fileList td a a.action.action-share{padding:17px 14px}.files-fileList td a a.action.action-share.permanent:not(.shared-style) .icon-shared+span{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}.files-fileList td a a.action.action-share .avatar{display:inline-block;vertical-align:middle}.files-fileList td a a.action.action-menu{padding-top:17px;padding-bottom:17px;padding-left:14px;padding-right:14px}.files-fileList td a a.action.no-permission:hover,.files-fileList td a a.action.no-permission:focus{opacity:.3}.files-fileList td a a.action.disabled:hover,.files-fileList td a a.action.disabled:focus,.files-fileList td a a.action.disabled img{opacity:.3}.files-fileList td a a.action.disabled.action-download{opacity:.7}.files-fileList td a a.action.disabled.action-download:hover,.files-fileList td a a.action.disabled.action-download:focus{opacity:.7}.files-fileList td a a.action:hover,.files-fileList td a a.action:focus{opacity:1}.files-fileList td a a.action:focus{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill)}.files-fileList td a .fileActionsMenu a.action,.files-fileList td a a.action.action-share.shared-style{opacity:.7}.files-fileList td a .fileActionsMenu .action.permanent{opacity:1}.files-fileList .action.action-share.permanent.shared-style span:not(.icon){display:inline-block;max-width:70px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;margin-left:6px}.files-fileList .remoteAddress .userDomain{margin-left:0 !important}.files-fileList .favorite-mark.permanent{opacity:1}.files-fileList .fileActionsMenu a.action:hover,.files-fileList .fileActionsMenu a.action:focus,.files-fileList a.action.action-share.shared-style:hover,.files-fileList a.action.action-share.shared-style:focus{opacity:1}.files-fileList tr a.action.disabled{background:none}.selectedActions a.download.disabled,.files-fileList tr a.action.action-download.disabled{color:#000}.files-fileList tr:hover a.action.disabled:hover *{cursor:default}.summary{color:var(--color-text-maxcontrast);height:330px}.files-filestable .summary .filesummary{width:100%;padding-left:101px}#body-public .summary{height:180px}.summary:hover,.summary:focus,.summary,table tr.summary td{background-color:rgba(0,0,0,0)}.summary td{border-bottom:none;vertical-align:top;padding-top:20px}.summary td:first-child{padding:0}.hiddeninfo{white-space:pre-line}table.dragshadow{width:auto;z-index:2000}table.dragshadow td.filename{padding-left:60px;padding-right:16px;height:36px;max-width:unset}table.dragshadow td.size{padding-right:8px}.mask{z-index:50;position:absolute;top:0;left:0;right:0;bottom:0;background-color:var(--color-main-background);background-repeat:no-repeat no-repeat;background-position:50%;opacity:.7;transition:opacity 100ms;-moz-transition:opacity 100ms;-o-transition:opacity 100ms;-ms-transition:opacity 100ms;-webkit-transition:opacity 100ms}.mask.transparent{opacity:0}.newFileMenu{font-weight:300;top:100%;left:-48px !important;margin-top:4px;min-width:100px;z-index:1001}.newFileMenu::after{left:61px !important}.files-controls{box-sizing:border-box;position:-webkit-sticky;position:sticky;height:50px;padding:0;margin:0;background-color:var(--color-main-background-translucent);z-index:62;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;top:0;padding-left:50px}.files-controls .actions>div>.button,.files-controls .actions>div button,.files-controls .actions>.button,.files-controls .actions button{box-sizing:border-box;display:inline-block;display:flex;height:44px;width:44px;padding:9px;align-items:center;justify-content:center}.files-controls .actions>div .button.hidden,.files-controls .actions .button.hidden{display:none}.viewer-mode #app-navigation+#app-content .files-controls{left:0}.files-filestable .filename .action .icon,.files-filestable .selectedActions a .icon,.files-filestable .filename .favorite-mark .icon,.files-controls .actions .button .icon{display:inline-block;vertical-align:middle;background-size:16px 16px}.files-filestable .filename .favorite-mark .icon-star{background-image:none}.files-filestable .filename .favorite-mark .icon-starred{background-image:var(--icon-starred-yellow) !important}.files-filestable .filename .action .icon.hidden,.files-filestable .selectedActions a .icon.hidden,.files-controls .actions .button .icon.hidden{display:none}.files-filestable .filename .action .icon.loading,.files-filestable .selectedActions a .icon.loading,.files-controls .actions .button .icon.loading{width:15px;height:15px}.app-files .actions .button.new{position:relative}.breadcrumb{align-items:center}.breadcrumb .icon-home{border-radius:var(--border-radius)}.breadcrumb .canDrop>a,.files-filestable tbody tr.canDrop{background-color:rgba(0,130,201,.3)}.dropzone-background{background-color:rgba(0,130,201,.3)}.dropzone-background :hover{box-shadow:none !important}.notCreatable{margin-left:12px;margin-right:44px;margin-top:12px;color:var(--color-main-text);overflow:auto;min-width:160px;height:54px}.notCreatable:not(.hidden){display:flex}.notCreatable .icon-alert-outline{top:-15px;position:relative;margin-right:4px}.quota-navigation-item{margin:0 !important;border:none;border-radius:0;background-color:rgba(0,0,0,0);z-index:1;height:44px;display:flex !important;flex-direction:column}.quota-navigation-item__text{height:30px}.quota-navigation-item[href="#"],.quota-navigation-item[href="#"] *{cursor:default !important}.quota-navigation-item__container{height:5px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) thead tr{display:block;border-bottom:1px solid var(--color-border);background-color:var(--color-main-background-translucent)}.files-filestable.view-grid:not(.hidden) thead tr th{width:auto;border:none}.files-filestable.view-grid:not(.hidden) tbody{display:grid;grid-template-columns:repeat(auto-fill, 160px);justify-content:space-around;row-gap:15px;margin:15px 0}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden){display:block;position:relative;height:190px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted{background-color:rgba(0,0,0,0)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .fileactions{background-color:var(--color-background-hover)}.files-filestable.view-grid:not(.hidden) tbody td{display:inline;border-bottom:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper{min-width:0;max-width:none;position:absolute;width:160px;height:160px;padding:14px;top:0;left:0;z-index:-1}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail{width:calc(100% - 2 * 14px);height:calc(100% - 2 * 14px);background-size:contain;margin:0;border-radius:var(--border-radius);background-repeat:no-repeat;background-position:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail .favorite-mark{left:auto;top:-11px;right:-11px}.files-filestable.view-grid:not(.hidden) tbody td.filename .uploadtext{width:100%;margin:0;top:0;bottom:auto;height:28px;padding-top:4px;padding-left:28px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name{height:100%;border-radius:var(--border-radius);overflow:hidden;cursor:pointer !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext{display:flex;height:44px;margin-top:146px;text-align:center;line-height:44px;padding:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{display:inline-block;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:before{content:"";flex:1;min-width:14px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:after{content:"";flex:1;min-width:44px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .extension{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .system-tags{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions{height:initial;margin-top:146px;display:flex;align-items:center;position:absolute;right:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action{padding:14px;width:44px;height:44px;display:flex;align-items:center;justify-content:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action:not(.action-menu){display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden .action-share img{padding:6px;border-radius:50%}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-restore-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-comment-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename form{padding:3px 14px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody td.filename form input.filename{width:100%;margin-left:0;cursor:text}.files-filestable.view-grid:not(.hidden) tbody td.filesize,.files-filestable.view-grid:not(.hidden) tbody td.date{display:none}.files-filestable.view-grid:not(.hidden) tbody td.selection,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark{position:absolute;top:-8px;left:-8px;display:flex;z-index:10}.files-filestable.view-grid:not(.hidden) tbody td.selection label,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label{width:44px;height:44px;display:inline-flex;padding:14px}.files-filestable.view-grid:not(.hidden) tbody td.selection label::before,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label::before{margin:0;width:14px;height:14px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:0;width:150px;margin:0 5px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu .menuitem span:not(.icon){overflow:hidden;text-overflow:ellipsis}.files-filestable.view-grid:not(.hidden) tr.hidden-file td.filename .name .nametext .extension{display:block}.files-filestable.view-grid:not(.hidden) tfoot{display:grid}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden){display:inline-block;margin:0 auto;height:418px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td{padding-top:50px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td:first-child,.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td.date{display:none}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td .info{margin-left:0}#view-toggle{background-color:var(--color-main-background-translucent);border:none;margin:0;padding:22px;opacity:.5;float:right;right:var(--default-grid-baseline);top:var(--default-grid-baseline);z-index:100;position:sticky}#view-toggle:hover,#view-toggle:focus,#showgridview:focus+#view-toggle{opacity:1}#view-toggle:focus-visible,#showgridview:focus-visible+#view-toggle{box-shadow:inset 0 0 0 2px var(--color-primary-element) !important}#showgridview{position:fixed;top:0}#body-public .files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{max-width:124px}#body-public .files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:-80px}#body-public #view-toggle{position:absolute;right:0;top:0}#gallery-button{display:none}#tag_multiple_files_container{overflow:hidden;background-color:#fff;border-radius:3px;position:relative;display:flex;flex-wrap:wrap;margin-bottom:10px}#tag_multiple_files_container h3{width:100%;padding:0 18px}#tag_multiple_files_container .systemTagsInputFieldContainer{flex:1 1 80%;min-width:0;margin:0 12px}/*# sourceMappingURL=files.css.map */ diff --git a/apps/files/css/files.css.map b/apps/files/css/files.css.map index 14c23a8f68d..09e55b847f1 100644 --- a/apps/files/css/files.css.map +++ b/apps/files/css/files.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["files.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAWA,SAEC,YACA,YACA,qBACA,WAED,oEACA,8BACA,kDAEC,+CAED,0BACC,oDAGD,mBACC,kBACA,aACA,SACA,4CACC,iBAIF,gBACC,aAGD,OACC,iBACA,YACA,aACA,aACA,mBAGD,6EAGC,yBACA,gCAID,kBACC,kBACA,WACA,gBACA,cACA,sBAEA,6CACC,aAGD,wBACC,wBACA,gBAEA,SAEA,WACA,cACA,0DAMD,wBACC,cACA,WAEA,mGAEC,8CAEA,6KACC,oCAKF,8DACC,oBAKH,yBACC,aAID,uCACC,cACA,WAGD,wBAGC,yBAEA,qBAGD,6FACC,+DAGD,iCACC,yDAGD,kFACC,0CAGD,4EACC,+DAID,gBCxEC,yCD2ED,iBC3EC,yCD8ED,oBC9EC,0CDiFD,yFCjFC,wCDuFD,uBCvFC,yCD0FD,2BC1FC,2CD6FD,mBC7FC,yCDgGD,2BChGC,4CDmGD,wBCnGC,0CDsGD,4BCtGC,4CD0GD,4CACC,WAGD,iCACC,WACA,YACA,eACA,SACA,eAGD,wCACC,aAGD,0CACC,WAGD,2BACC,YAED,4KAKC,+CAED,wMAKC,oDAGD,qCAEA,yDACC,oCAED,kCACC,iCACA,8BACA,4BACA,yBACA,mBAED,wGAIC,UACA,oCAGD,oBACC,oCAED,uBACC,6BAED,sBACC,cACA,aACA,YACA,sBACA,2BACA,sBACA,oCACC,kBAGF,kCACC,qBACA,mBAED,2BACC,eACA,iBAGD,uCACC,cAGD,yBACC,WACA,WACA,gBACA,qBACA,2BACA,WAED,wJAIC,kBAED,2CACC,eAED,4EAEC,mBAGD,kBAEC,4CACA,gBACA,mBAED,SACC,eACA,kBACA,+BACA,4BAED,qBACC,kBACA,aACA,UAGD,uBACC,kBACA,YAGD,0BACC,gBAED,uCACC,iBAED,8EAEC,2BACA,sBACA,kBAEA,gBAGD,qMAQC,gBACA,qPACC,MAIF,2BACC,0DACA,iBAGD,sDACC,iBAGD,+BACC,kBACA,aAED,kCACC,aAGD,0DAGC,WACA,kBAED,kDAEC,aACA,kBACA,2BACA,sBACA,YACA,iBACA,UAED,qCAEC,QACA,eACA,eACA,YAGA,8DACC,WAED,mEACC,WAGF,6BACC,qBACA,WACA,YACA,wBACA,2BACA,4BACA,gBACA,eACA,mCACA,eACA,kBACA,UAED,oCACC,eAID,2CACC,qCAGD,iDACC,qBACA,4BACA,YAED,uBACC,iBACA,kBACA,SAGD,6IACA,8FAEA,wCACC,kBACA,gBACA,uBACA,YAKA,kBACC,YACA,4BACC,QACA,YACA,aACA,gBACA,mBACA,uBACA,YACA,WACA,mBAID,+BACC,iBACA,aACA,uBACA,mBACA,kCACA,gBAEA,iDACC,iBACA,iBACA,wCACA,iCACA,oCACA,uBACA,mBACA,gBACA,uBACA,iBACA,kBAEA,uDACC,iBACA,sBAID,mEACC,gBAOL,iJAEC,wBAGD,mCACC,iCACA,8BACA,4BACA,yBAED,4BACC,WAGD,2CACC,uBACA,gBACA,kBACA,mBAKD,8BACC,kBACA,mBAEA,iBACA,OACA,SACA,YACA,cAEA,iBACA,eAEA,iBACA,oCACA,uBACA,mBAGD,mBACC,UAID,6DACC,WACA,eAID,iRAIC,UAID,0EACC,WAMA,wEACC,aAGD,oGACC,+CACA,wCACA,wBACA,yDACA,aAIF,oGAEC,mBAGD,+BACC,kBACA,WACA,eACA,gBACA,wJAGD,wFAEC,kBACA,UACA,YAGD,yCACC,qBACA,WAED,8CACC,kBACA,cACA,SACA,WACA,iBACA,kBACA,wDAEC,8CACA,8CACA,oBAEA,WACA,YACA,aACA,qBACA,uBAGF,8DACC,+CAGD,iDAGA,aACC,WAGD,iCACC,kBAID,mDAEC,gBAID,oCACC,qBACA,0BAGD,8EACC,0BAOA,kCACC,eAGD,sEACC,eAGD,sCACC,gBAIF,aACC,YACA,WACA,2BAGD,qCACC,wCAID,iBACI,kBACA,qBACA,sBAEJ,wBACI,aAEJ,mBACC,eACA,iBACA,iBAGD,0BACC,aAED,uBACC,kBACA,2BACA,mBAGD,8CACC,gBAIA,8BACC,eACA,iBACA,iBACA,WACA,2CACC,kBACA,0FAGC,kBACA,cACA,SACA,UACA,WACA,gBAED,mDACC,qBACA,sBAGF,0CACC,iBACA,oBACA,kBACA,mBAGA,oGACC,WAID,qIAEC,WAED,uDACC,WACA,0HACC,WAIH,wEACC,UAED,oCACC,+CACA,wCAGF,uGACC,WAED,wDACC,UAKF,4EACC,qBACA,eACA,gBACA,uBACA,sBACA,gBAGD,2CACC,yBAGD,yCACC,UAGD,kNAKC,UAGD,qCACC,gBAGD,0FAEC,WAGD,mDACC,eAGD,SACC,oCAGA,aAED,wCACC,WAEA,mBAKD,sBACC,aAED,2DAIC,+BAED,YACC,mBACA,mBACA,iBAED,wBACC,UAED,YACC,qBAGD,iBACC,WACA,aAED,6BACC,kBACA,mBACA,YAGA,gBAED,yBACC,kBAED,MACC,WACA,kBACA,MACA,OACA,QACA,SACA,8CACA,sCACA,wBACA,WACA,yBACA,8BACA,4BACA,6BACA,iCAED,kBACC,UAGD,aACC,gBACA,SACA,sBACA,eACA,gBACA,aAGA,oBACC,qBAKF,gBACC,sBACA,wBACA,gBACA,YACA,UACA,SACA,0DACA,WACA,yBACA,sBACA,qBACA,iBACA,aACA,MACA,kBAKE,0IACC,sBACA,qBACA,aACA,YACA,WACA,YACA,mBACA,uBAED,oFACC,aAQJ,0DACC,OAGD,6KAIC,qBACA,sBACA,0BAMA,sDACC,sBAED,yDACC,uDAIF,iJAGC,aAGD,oJAGC,WACA,YAGD,gCACC,kBAGD,YACC,mBAEA,uBACC,mCAIF,0DAEC,oCAED,qBACC,oCACA,4BACC,2BAIF,cACC,iBACA,kBACA,gBACA,6BACA,cACA,gBACA,YAEA,2BACC,aAGD,kCACC,UACA,kBACA,iBAIF,uBACC,oBACA,YACA,gBACA,+BACA,UACA,YACA,wBACA,sBAEA,6BACC,YAKA,oEACC,0BAIF,kCACC,WACA,mCAWA,kDACC,cACA,4CACA,0DACA,qDACC,WACA,YAMH,+CACC,aACA,+CACA,6BACA,aACA,cAGA,+DACC,cACA,kBACA,aACA,mCAEA,0fAKC,+BAEA,oxDAGC,+CAKH,kDACC,eACA,mBAGC,8EACC,YACA,eACA,kBACA,MAvDQ,MAwDR,OAxDQ,MAyDR,QAxDO,KAyDP,MACA,OACA,WAEA,yFACC,4BACA,6BACA,wBACA,SACA,mCACA,4BACA,2BAKA,wGACC,UACA,UACA,YAKH,uEACC,WACA,SACA,MACA,YAEA,YACA,gBAEA,kBAGD,iEACC,YACA,mCAIA,gBAKA,0BAEA,2EACC,aACA,YACA,iBACA,kBACA,iBACA,UAEA,0FACC,qBACA,kBACA,gBACA,uBACA,mBAED,kFACC,WACA,OACA,eAED,iFACC,WACA,OACA,eAID,sFACC,aAKF,8EACC,aAGD,8EACC,eACA,iBACA,aACA,mBACA,kBACA,QAEA,sFACC,QAxJK,KAyJL,WACA,YACA,aACA,mBACA,uBAGA,wGACC,aAQH,2GACC,yBAEA,6HACC,YACA,kBAIF,6GACC,yBAGD,6GACC,yBAIF,gEACC,iBACA,mCAEA,+EACC,WACA,cACA,YAMH,kHAEC,aAGD,sIAEC,kBACA,SACA,UACA,aACA,WAEA,kJACC,WACA,YACA,oBACA,QAzNO,KA0NP,kKACC,SACA,MA5NM,KA6NN,OA7NM,KAmOT,+DACC,OACA,YACA,aAGA,yFACC,gBACA,uBAMJ,+FACC,cAID,+CACC,aAEA,qEACC,qBACA,cAEA,aAEA,wEACC,iBAEA,iKAEC,aAGD,8EACI,cAQR,aACC,0DACA,YACA,SACA,aACA,WACA,YACA,mCACA,iCACA,YACA,gBAEA,uEAGC,UAGD,oEAEC,mEASF,cACC,eACA,MAOC,uGACC,gBAID,4EACC,WAKF,0BACC,kBACA,QACA,MAKF,gBACC,aAGD,8BACC,gBACA,sBACA,kBACA,kBACA,aACA,eACA,mBAEA,iCACC,WACA,eAGD,6DACC,aACA,YACA","file":"files.css"}
\ No newline at end of file +{"version":3,"sourceRoot":"","sources":["files.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAWA,SAEC,YACA,YACA,qBACA,WAED,oEACA,8BACA,kDAEC,+CAED,0BACC,oDAGD,mBACC,kBACA,aACA,SACA,4CACC,iBAIF,gBACC,aAGD,OACC,iBACA,YACA,aACA,aACA,mBAGD,6EAGC,yBACA,gCAID,kBACC,kBACA,WACA,gBACA,cACA,sBAEA,6CACC,aAGD,wBACC,wBACA,gBAEA,SAEA,WACA,cACA,0DAMD,wBACC,cACA,WAEA,mGAEC,8CAEA,6KACC,oCAKF,8DACC,oBAKH,yBACC,aAID,uCACC,cACA,WAGD,wBAGC,yBAEA,qBAGD,6FACC,+DAGD,iCACC,yDAGD,kFACC,0CAGD,4EACC,+DAID,gBCxEC,yCD2ED,iBC3EC,yCD8ED,oBC9EC,0CDiFD,qGCjFC,wCDuFD,0BCvFC,yCD0FD,2BC1FC,2CD6FD,mBC7FC,yCDgGD,2BChGC,4CDmGD,2BCnGC,0CDsGD,4BCtGC,4CD0GD,4CACC,WAGD,iCACC,WACA,YACA,eACA,SACA,eAGD,wCACC,aAGD,0CACC,WAGD,2BACC,YAED,4KAKC,+CAED,wMAKC,oDAGD,qCAEA,yDACC,oCAED,kCACC,iCACA,8BACA,4BACA,yBACA,mBAED,wGAIC,UACA,oCAGD,oBACC,oCAED,uBACC,6BAED,sBACC,cACA,aACA,YACA,sBACA,2BACA,sBACA,oCACC,kBAGF,kCACC,qBACA,mBAED,2BACC,eACA,iBAGD,uCACC,cAGD,yBACC,WACA,WACA,gBACA,qBACA,2BACA,WAED,wJAIC,kBAED,2CACC,eAED,4EAEC,mBAGD,kBAEC,4CACA,gBACA,mBAED,SACC,eACA,kBACA,+BACA,4BAED,qBACC,kBACA,aACA,UAGD,uBACC,kBACA,YAGD,0BACC,gBAED,uCACC,iBAED,8EAEC,2BACA,sBACA,kBAEA,gBAGD,qMAQC,gBACA,qPACC,MAIF,2BACC,0DACA,iBAGD,sDACC,iBAGD,+BACC,kBACA,aAED,kCACC,aAGD,0DAGC,WACA,kBAED,kDAEC,aACA,kBACA,2BACA,sBACA,YACA,iBACA,UAED,qCAEC,QACA,eACA,eACA,YAGA,8DACC,WAED,mEACC,WAGF,6BACC,qBACA,WACA,YACA,wBACA,2BACA,4BACA,gBACA,eACA,mCACA,eACA,kBACA,UAED,oCACC,eAID,2CACC,qCAGD,iDACC,qBACA,4BACA,YAED,uBACC,iBACA,kBACA,SAGD,6IACA,8FAEA,wCACC,kBACA,gBACA,uBACA,YAKA,kBACC,YACA,4BACC,QACA,YACA,aACA,gBACA,mBACA,uBACA,YACA,WACA,mBAID,+BACC,iBACA,aACA,uBACA,mBACA,kCACA,gBAEA,iDACC,iBACA,iBACA,wCACA,iCACA,oCACA,uBACA,mBACA,gBACA,uBACA,iBACA,kBAEA,uDACC,iBACA,sBAID,mEACC,gBAOL,iJAEC,wBAGD,mCACC,iCACA,8BACA,4BACA,yBAED,4BACC,WAGD,2CACC,uBACA,gBACA,kBACA,mBAKD,8BACC,kBACA,mBAEA,iBACA,OACA,SACA,YACA,cAEA,iBACA,eAEA,iBACA,oCACA,uBACA,mBAGD,mBACC,UAID,6DACC,WACA,eAID,iRAIC,UAID,0EACC,WAMA,wEACC,aAGD,oGACC,+CACA,wCACA,wBACA,yDACA,aAIF,oGAEC,mBAGD,+BACC,kBACA,WACA,eACA,gBACA,wJAGD,wFAEC,kBACA,UACA,YAGD,yCACC,qBACA,WAED,8CACC,kBACA,cACA,SACA,WACA,iBACA,kBACA,wDAEC,8CACA,8CACA,oBAEA,WACA,YACA,aACA,qBACA,uBAGF,8DACC,+CAGD,iDAGA,aACC,WAGD,iCACC,kBAID,mDAEC,gBAID,oCACC,qBACA,0BAGD,8EACC,0BAOA,kCACC,eAGD,sEACC,eAGD,sCACC,gBAIF,aACC,YACA,WACA,2BAGD,qCACC,wCAID,iBACI,kBACA,qBACA,sBAEJ,wBACI,aAEJ,mBACC,eACA,iBACA,iBAGD,0BACC,aAED,uBACC,kBACA,2BACA,mBAGD,8CACC,gBAIA,8BACC,eACA,iBACA,iBACA,WACA,2CACC,kBACA,0FAGC,kBACA,cACA,SACA,UACA,WACA,gBAED,mDACC,qBACA,sBAGF,0CACC,iBACA,oBACA,kBACA,mBAGA,oGACC,WAID,qIAEC,WAED,uDACC,WACA,0HACC,WAIH,wEACC,UAED,oCACC,+CACA,wCAGF,uGACC,WAED,wDACC,UAKF,4EACC,qBACA,eACA,gBACA,uBACA,sBACA,gBAGD,2CACC,yBAGD,yCACC,UAGD,kNAKC,UAGD,qCACC,gBAGD,0FAEC,WAGD,mDACC,eAGD,SACC,oCAGA,aAED,wCACC,WAEA,mBAKD,sBACC,aAED,2DAIC,+BAED,YACC,mBACA,mBACA,iBAED,wBACC,UAED,YACC,qBAGD,iBACC,WACA,aAED,6BACC,kBACA,mBACA,YAGA,gBAED,yBACC,kBAED,MACC,WACA,kBACA,MACA,OACA,QACA,SACA,8CACA,sCACA,wBACA,WACA,yBACA,8BACA,4BACA,6BACA,iCAED,kBACC,UAGD,aACC,gBACA,SACA,sBACA,eACA,gBACA,aAGA,oBACC,qBAKF,gBACC,sBACA,wBACA,gBACA,YACA,UACA,SACA,0DACA,WACA,yBACA,sBACA,qBACA,iBACA,aACA,MACA,kBAKE,0IACC,sBACA,qBACA,aACA,YACA,WACA,YACA,mBACA,uBAED,oFACC,aAQJ,0DACC,OAGD,6KAIC,qBACA,sBACA,0BAMA,sDACC,sBAED,yDACC,uDAIF,iJAGC,aAGD,oJAGC,WACA,YAGD,gCACC,kBAGD,YACC,mBAEA,uBACC,mCAIF,0DAEC,oCAED,qBACC,oCACA,4BACC,2BAIF,cACC,iBACA,kBACA,gBACA,6BACA,cACA,gBACA,YAEA,2BACC,aAGD,kCACC,UACA,kBACA,iBAIF,uBACC,oBACA,YACA,gBACA,+BACA,UACA,YACA,wBACA,sBAEA,6BACC,YAKA,oEACC,0BAIF,kCACC,WACA,mCAWA,kDACC,cACA,4CACA,0DACA,qDACC,WACA,YAMH,+CACC,aACA,+CACA,6BACA,aACA,cAGA,+DACC,cACA,kBACA,aACA,mCAEA,0fAKC,+BAEA,oxDAGC,+CAKH,kDACC,eACA,mBAGC,8EACC,YACA,eACA,kBACA,MAvDQ,MAwDR,OAxDQ,MAyDR,QAxDO,KAyDP,MACA,OACA,WAEA,yFACC,4BACA,6BACA,wBACA,SACA,mCACA,4BACA,2BAKA,wGACC,UACA,UACA,YAKH,uEACC,WACA,SACA,MACA,YAEA,YACA,gBAEA,kBAGD,iEACC,YACA,mCAIA,gBAKA,0BAEA,2EACC,aACA,YACA,iBACA,kBACA,iBACA,UAEA,0FACC,qBACA,kBACA,gBACA,uBACA,mBAED,kFACC,WACA,OACA,eAED,iFACC,WACA,OACA,eAID,sFACC,aAKF,8EACC,aAGD,8EACC,eACA,iBACA,aACA,mBACA,kBACA,QAEA,sFACC,QAxJK,KAyJL,WACA,YACA,aACA,mBACA,uBAGA,wGACC,aAQH,2GACC,yBAEA,6HACC,YACA,kBAIF,6GACC,yBAGD,6GACC,yBAIF,gEACC,iBACA,mCAEA,+EACC,WACA,cACA,YAMH,kHAEC,aAGD,sIAEC,kBACA,SACA,UACA,aACA,WAEA,kJACC,WACA,YACA,oBACA,QAzNO,KA0NP,kKACC,SACA,MA5NM,KA6NN,OA7NM,KAmOT,+DACC,OACA,YACA,aAGA,yFACC,gBACA,uBAMJ,+FACC,cAID,+CACC,aAEA,qEACC,qBACA,cAEA,aAEA,wEACC,iBAEA,iKAEC,aAGD,8EACI,cAQR,aACC,0DACA,YACA,SACA,aACA,WACA,YACA,mCACA,iCACA,YACA,gBAEA,uEAGC,UAGD,oEAEC,mEASF,cACC,eACA,MAOC,uGACC,gBAID,4EACC,WAKF,0BACC,kBACA,QACA,MAKF,gBACC,aAGD,8BACC,gBACA,sBACA,kBACA,kBACA,aACA,eACA,mBAEA,iCACC,WACA,eAGD,6DACC,aACA,YACA","file":"files.css"}
\ No newline at end of file diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss index 0437ad79875..369e13021d0 100644 --- a/apps/files/css/files.scss +++ b/apps/files/css/files.scss @@ -144,13 +144,13 @@ .nav-icon-favorites { @include icon-color('starred', 'actions', variables.$color-black, 2, true); } -.nav-icon-sharingin, -.nav-icon-sharingout, -.nav-icon-pendingshares, -.nav-icon-shareoverview { +.nav-icon-sharinginOld, +.nav-icon-sharingoutOld, +.nav-icon-pendingsharesOld, +.nav-icon-shareoverviewOld { @include icon-color('share', 'files', variables.$color-black); } -.nav-icon-sharinglinks { +.nav-icon-sharinglinksOld { @include icon-color('public', 'files', variables.$color-black); } .nav-icon-extstoragemounts { @@ -162,7 +162,7 @@ .nav-icon-trashbin-starred { @include icon-color('delete', 'files', #ff0000); } -.nav-icon-deletedshares { +.nav-icon-deletedsharesOld { @include icon-color('unshare', 'files', variables.$color-black); } .nav-icon-favorites-starred { diff --git a/apps/files/css/merged.css b/apps/files/css/merged.css index 38574ea3b86..9f99f1b4073 100644 --- a/apps/files/css/merged.css +++ b/apps/files/css/merged.css @@ -1 +1 @@ -.actions{padding:3px;height:100%;display:inline-block;float:left}.actions input,.actions button,.actions .button{margin:0;float:left}.actions .button a{color:#555}.actions .button a:hover,.actions .button a:focus{background-color:var(--color-background-hover)}.actions .button a:active{background-color:var(--color-primary-element-light)}.actions.creatable{position:relative;display:flex;flex:1 1}.actions.creatable .button:not(:last-child){margin-right:3px}.actions.hidden{display:none}#trash{margin-right:8px;float:right;z-index:1010;padding:10px;font-weight:normal}.newFileMenu .error,.newFileMenu .error+.icon-confirm,.files-fileList .error{color:var(--color-error);border-color:var(--color-error)}.files-filestable{position:relative;width:100%;min-width:250px;display:block;flex-direction:column}.emptycontent:not(.hidden)~.files-filestable{display:none}.files-filestable thead{position:-webkit-sticky;position:sticky;top:44px;z-index:60;display:block;background-color:var(--color-main-background-translucent)}.files-filestable tbody{display:table;width:100%}.files-filestable tbody tr[data-permissions="0"],.files-filestable tbody tr[data-permissions="16"]{background-color:var(--color-background-dark)}.files-filestable tbody tr[data-permissions="0"] td.filename .nametext .innernametext,.files-filestable tbody tr[data-permissions="16"] td.filename .nametext .innernametext{color:var(--color-text-maxcontrast)}.files-filestable tbody tr[data-e2eencrypted=true] .selection{pointer-events:none}.files-filestable.hidden{display:none}.app-files #app-content>.viewcontainer{min-height:0%;width:100%}.app-files #app-content{width:calc(100% - 300px);overflow-anchor:none}.file-drag,.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:var(--color-primary-element-light) !important}.app-files #app-content.dir-drop{background-color:var(--color-main-background) !important}.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:rgba(0,0,0,0) !important}.app-files #app-content.dir-drop .files-filestable tbody tr.dropping-to-dir{background-color:var(--color-primary-element-light) !important}.nav-icon-files{background-image:var(--icon-folder-dark)}.nav-icon-recent{background-image:var(--icon-recent-dark)}.nav-icon-favorites{background-image:var(--icon-starred-dark)}.nav-icon-sharingin,.nav-icon-sharingout,.nav-icon-pendingshares,.nav-icon-shareoverview{background-image:var(--icon-share-dark)}.nav-icon-sharinglinks{background-image:var(--icon-public-dark)}.nav-icon-extstoragemounts{background-image:var(--icon-external-dark)}.nav-icon-trashbin{background-image:var(--icon-delete-dark)}.nav-icon-trashbin-starred{background-image:var(--icon-delete-#ff0000)}.nav-icon-deletedshares{background-image:var(--icon-unshare-dark)}.nav-icon-favorites-starred{background-image:var(--icon-starred-yellow)}#app-navigation .nav-files a.nav-icon-files{width:auto}#app-navigation .nav-files a.new{width:40px;height:32px;padding:0 10px;margin:0;cursor:pointer}#app-navigation .nav-files a.new.hidden{display:none}#app-navigation .nav-files a.new.disabled{opacity:.3}.files-filestable tbody tr{height:51px}.files-filestable tbody tr:hover,.files-filestable tbody tr:focus,.files-filestable tbody .name:focus,.files-filestable tbody tr:hover .filename form,table tr.mouseOver td{background-color:var(--color-background-hover)}.files-filestable tbody tr:active,.files-filestable tbody tr.highlighted,.files-filestable tbody tr.highlighted .name:focus,.files-filestable tbody tr.selected,.files-filestable tbody tr.searchresult{background-color:var(--color-primary-element-light)}tbody a{color:var(--color-main-text)}span.conflict-path,span.extension,span.uploading,td.date{color:var(--color-text-maxcontrast)}span.conflict-path,span.extension{-webkit-transition:opacity 300ms;-moz-transition:opacity 300ms;-o-transition:opacity 300ms;transition:opacity 300ms;vertical-align:top}tr:hover span.conflict-path,tr:focus span.conflict-path,tr:hover span.extension,tr:focus span.extension{opacity:1;color:var(--color-text-maxcontrast)}table th,table th a{color:var(--color-text-maxcontrast)}table.multiselect th a{color:var(--color-main-text)}table th .columntitle{display:block;padding:15px;height:50px;box-sizing:border-box;-moz-box-sizing:border-box;vertical-align:middle}table th .columntitle:focus-visible{border-radius:2px}table.multiselect th .columntitle{display:inline-block;margin-right:-20px}table th .columntitle.name{padding-left:0;margin-left:44px}table.multiselect th .columntitle.name{margin-left:0}table th .sort-indicator{width:10px;height:8px;margin-left:5px;display:inline-block;vertical-align:text-bottom;opacity:.3}.sort-indicator.hidden,.multiselect .sort-indicator,table.multiselect th:hover .sort-indicator.hidden,table.multiselect th:focus .sort-indicator.hidden{visibility:hidden}.multiselect .sort,.multiselect .sort span{cursor:default}table th:hover .sort-indicator.hidden,table th:focus .sort-indicator.hidden{visibility:visible}table th,table td{border-bottom:1px solid var(--color-border);text-align:left;font-weight:normal}table td{padding:0 15px;font-style:normal;background-position:8px center;background-repeat:no-repeat}table th.column-name{position:relative;width:9999px;padding:0}.column-name-container{position:relative;height:50px}table th.column-selection{padding-top:2px}table th.column-size,table td.filesize{text-align:right}table th.column-mtime,table td.date,table th.column-last,table td.column-last{-moz-box-sizing:border-box;box-sizing:border-box;position:relative;min-width:130px}#app-content-recent,#app-content-favorites,#app-content-shareoverview,#app-content-sharingout,#app-content-sharingin,#app-content-sharinglinks,#app-content-deletedshares,#app-content-pendingshares{margin-top:22px}#app-content-recent thead,#app-content-favorites thead,#app-content-shareoverview thead,#app-content-sharingout thead,#app-content-sharingin thead,#app-content-sharinglinks thead,#app-content-deletedshares thead,#app-content-pendingshares thead{top:0}table.multiselect thead th{background-color:var(--color-main-background-translucent);font-weight:bold}#app-content.with-app-sidebar table.multiselect thead{margin-right:27%}table.multiselect .column-name{position:relative;width:9999px}table.multiselect .column-mtime>a{display:none}table td.selection,table th.selection,table td.fileaction{width:32px;text-align:center}table td.filename a.name,table td.filename p.name{display:flex;position:relative;-moz-box-sizing:border-box;box-sizing:border-box;height:50px;line-height:50px;padding:0}table td.filename .thumbnail-wrapper{width:0;min-width:50px;max-width:50px;height:50px}table td.filename .thumbnail-wrapper.icon-loading-small:after{z-index:10}table td.filename .thumbnail-wrapper.icon-loading-small .thumbnail{opacity:.2}table td.filename .thumbnail{display:inline-block;width:32px;height:32px;background-size:contain;background-position:center;background-repeat:no-repeat;margin-left:9px;margin-top:9px;border-radius:var(--border-radius);cursor:pointer;position:absolute;z-index:4}table td.filename p.name .thumbnail{cursor:default}table tr[data-has-preview=true] .thumbnail{border:1px solid var(--color-border)}table:not(.view-grid) td.filename input.filename{width:70% !important;margin-left:48px !important;cursor:text}table td.filename form{margin-top:-40px;position:relative;top:-6px}table td.filename a,table td.login,table td.logout,table td.download,table td.upload,table td.create,table td.delete{padding:3px 8px 8px 3px}table td.filename .nametext,.modified,.column-last>span:first-child{float:left;padding:15px 0}.modified,.column-last>span:first-child{position:relative;overflow:hidden;text-overflow:ellipsis;width:110px}table td.filename{max-width:0}table td.filename .nametext{width:0;flex-grow:1;display:flex;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;height:100%;z-index:10;padding:0 20px 0 0}table td.filename .system-tags{--min-size: 32px;display:flex;justify-content:center;align-items:center;min-width:calc(var(--min-size)*2);max-width:300px}table td.filename .system-tags .system-tags__tag{padding:5px 10px;border:1px solid;border-radius:var(--border-radius-pill);border-color:var(--color-border);color:var(--color-text-maxcontrast);height:var(--min-size);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:22px;text-align:center}table td.filename .system-tags .system-tags__tag--more{overflow:visible;text-overflow:initial}table td.filename .system-tags .system-tags__tag+.system-tags__tag{margin-left:5px}.hide-hidden-files .files-filestable .files-fileList tr.hidden-file,.hide-hidden-files .files-filestable .files-fileList tr.hidden-file.dragging{display:none !important}.files-fileList tr.animate-opacity{-webkit-transition:opacity 250ms;-moz-transition:opacity 250ms;-o-transition:opacity 250ms;transition:opacity 250ms}.files-fileList tr.dragging{opacity:.2}table td.filename .nametext .innernametext{text-overflow:ellipsis;overflow:hidden;position:relative;vertical-align:top}table td.filename .uploadtext{position:absolute;font-weight:normal;margin-left:50px;left:0;bottom:0;height:20px;padding:0 4px;padding-left:1px;font-size:11px;line-height:22px;color:var(--color-text-maxcontrast);text-overflow:ellipsis;white-space:nowrap}table td.selection{padding:0}.files-fileList tr td.selection>.selectCheckBox+label:before{opacity:.3;margin-right:0}.files-fileList tr:hover td.selection>.selectCheckBox+label:before,.files-fileList tr:focus td.selection>.selectCheckBox+label:before,.files-fileList tr td.selection>.selectCheckBox:checked+label:before,.files-fileList tr.selected td.selection>.selectCheckBox+label:before{opacity:1}.files-fileList tr.halfselected td.selection>.selectCheckBox+label:before{opacity:.5}.files-fileList tr td.selection>.selectCheckBox+label,.select-all+label{padding:16px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill);outline:none !important;border:2px solid var(--color-primary-element) !important;padding:14px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{outline-offset:0px}.files-fileList tr td.filename{position:relative;width:100%;padding-left:0;padding-right:0;-webkit-transition:background-image 500ms;-moz-transition:background-image 500ms;-o-transition:background-image 500ms;transition:background-image 500ms}.files-fileList tr td.filename a.name label,.files-fileList tr td.filename p.name label{position:absolute;width:80%;height:50px}.files-fileList tr td.filename .favorite{display:inline-block;float:left}.files-fileList tr td.filename .favorite-mark{position:absolute;display:block;top:-8px;right:-8px;line-height:100%;text-align:center}.files-fileList tr td.filename .favorite-mark.permanent{background-color:var(--color-main-background);mask:var(--icon-star-rounded-white) no-repeat;mask-size:22px 22px;width:22px;height:22px;display:flex;align-content:center;justify-content:center}.files-fileList tr:hover td.filename .favorite-mark.permanent{background-color:var(--color-background-hover)}#uploadsize-message,#delete-confirm{display:none}.fileactions{z-index:50}.busy .fileactions,.busy .action{visibility:hidden}.bubble,#app-navigation .app-navigation-entry-menu{min-width:100px}.files-fileList .icon-loading-small{opacity:1 !important;display:inline !important}.files-fileList .action.action-share-notification span,.files-fileList a.name{cursor:default !important}.files-fileList a.name.disabled *{cursor:default}.files-fileList a.name.disabled a,.files-fileList a.name.disabled a *{cursor:pointer}.files-fileList a.name.disabled:focus{background:none}a.action>img{height:16px;width:16px;vertical-align:text-bottom}a.action.action-editlocally img.icon{filter:var(--background-invert-if-dark)}.selectedActions{position:relative;display:inline-block;vertical-align:middle}.selectedActions.hidden{display:none}.selectedActions a{display:inline;line-height:50px;padding:16px 5px}.selectedActions a.hidden{display:none}.selectedActions a img{position:relative;vertical-align:text-bottom;margin-bottom:-1px}.selectedActions .actions-selected .icon-more{margin-top:-3px}.files-fileList td a a.action{display:inline;padding:17px 8px;line-height:50px;opacity:.3}.files-fileList td a a.action.action-share{padding:17px 14px}.files-fileList td a a.action.action-share.permanent:not(.shared-style) .icon-shared+span{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}.files-fileList td a a.action.action-share .avatar{display:inline-block;vertical-align:middle}.files-fileList td a a.action.action-menu{padding-top:17px;padding-bottom:17px;padding-left:14px;padding-right:14px}.files-fileList td a a.action.no-permission:hover,.files-fileList td a a.action.no-permission:focus{opacity:.3}.files-fileList td a a.action.disabled:hover,.files-fileList td a a.action.disabled:focus,.files-fileList td a a.action.disabled img{opacity:.3}.files-fileList td a a.action.disabled.action-download{opacity:.7}.files-fileList td a a.action.disabled.action-download:hover,.files-fileList td a a.action.disabled.action-download:focus{opacity:.7}.files-fileList td a a.action:hover,.files-fileList td a a.action:focus{opacity:1}.files-fileList td a a.action:focus{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill)}.files-fileList td a .fileActionsMenu a.action,.files-fileList td a a.action.action-share.shared-style{opacity:.7}.files-fileList td a .fileActionsMenu .action.permanent{opacity:1}.files-fileList .action.action-share.permanent.shared-style span:not(.icon){display:inline-block;max-width:70px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;margin-left:6px}.files-fileList .remoteAddress .userDomain{margin-left:0 !important}.files-fileList .favorite-mark.permanent{opacity:1}.files-fileList .fileActionsMenu a.action:hover,.files-fileList .fileActionsMenu a.action:focus,.files-fileList a.action.action-share.shared-style:hover,.files-fileList a.action.action-share.shared-style:focus{opacity:1}.files-fileList tr a.action.disabled{background:none}.selectedActions a.download.disabled,.files-fileList tr a.action.action-download.disabled{color:#000}.files-fileList tr:hover a.action.disabled:hover *{cursor:default}.summary{color:var(--color-text-maxcontrast);height:330px}.files-filestable .summary .filesummary{width:100%;padding-left:101px}#body-public .summary{height:180px}.summary:hover,.summary:focus,.summary,table tr.summary td{background-color:rgba(0,0,0,0)}.summary td{border-bottom:none;vertical-align:top;padding-top:20px}.summary td:first-child{padding:0}.hiddeninfo{white-space:pre-line}table.dragshadow{width:auto;z-index:2000}table.dragshadow td.filename{padding-left:60px;padding-right:16px;height:36px;max-width:unset}table.dragshadow td.size{padding-right:8px}.mask{z-index:50;position:absolute;top:0;left:0;right:0;bottom:0;background-color:var(--color-main-background);background-repeat:no-repeat no-repeat;background-position:50%;opacity:.7;transition:opacity 100ms;-moz-transition:opacity 100ms;-o-transition:opacity 100ms;-ms-transition:opacity 100ms;-webkit-transition:opacity 100ms}.mask.transparent{opacity:0}.newFileMenu{font-weight:300;top:100%;left:-48px !important;margin-top:4px;min-width:100px;z-index:1001}.newFileMenu::after{left:61px !important}.files-controls{box-sizing:border-box;position:-webkit-sticky;position:sticky;height:50px;padding:0;margin:0;background-color:var(--color-main-background-translucent);z-index:62;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;top:0;padding-left:50px}.files-controls .actions>div>.button,.files-controls .actions>div button,.files-controls .actions>.button,.files-controls .actions button{box-sizing:border-box;display:inline-block;display:flex;height:44px;width:44px;padding:9px;align-items:center;justify-content:center}.files-controls .actions>div .button.hidden,.files-controls .actions .button.hidden{display:none}.viewer-mode #app-navigation+#app-content .files-controls{left:0}.files-filestable .filename .action .icon,.files-filestable .selectedActions a .icon,.files-filestable .filename .favorite-mark .icon,.files-controls .actions .button .icon{display:inline-block;vertical-align:middle;background-size:16px 16px}.files-filestable .filename .favorite-mark .icon-star{background-image:none}.files-filestable .filename .favorite-mark .icon-starred{background-image:var(--icon-starred-yellow) !important}.files-filestable .filename .action .icon.hidden,.files-filestable .selectedActions a .icon.hidden,.files-controls .actions .button .icon.hidden{display:none}.files-filestable .filename .action .icon.loading,.files-filestable .selectedActions a .icon.loading,.files-controls .actions .button .icon.loading{width:15px;height:15px}.app-files .actions .button.new{position:relative}.breadcrumb{align-items:center}.breadcrumb .icon-home{border-radius:var(--border-radius)}.breadcrumb .canDrop>a,.files-filestable tbody tr.canDrop{background-color:rgba(0,130,201,.3)}.dropzone-background{background-color:rgba(0,130,201,.3)}.dropzone-background :hover{box-shadow:none !important}.notCreatable{margin-left:12px;margin-right:44px;margin-top:12px;color:var(--color-main-text);overflow:auto;min-width:160px;height:54px}.notCreatable:not(.hidden){display:flex}.notCreatable .icon-alert-outline{top:-15px;position:relative;margin-right:4px}.quota-navigation-item{margin:0 !important;border:none;border-radius:0;background-color:rgba(0,0,0,0);z-index:1;height:44px;display:flex !important;flex-direction:column}.quota-navigation-item__text{height:30px}.quota-navigation-item[href="#"],.quota-navigation-item[href="#"] *{cursor:default !important}.quota-navigation-item__container{height:5px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) thead tr{display:block;border-bottom:1px solid var(--color-border);background-color:var(--color-main-background-translucent)}.files-filestable.view-grid:not(.hidden) thead tr th{width:auto;border:none}.files-filestable.view-grid:not(.hidden) tbody{display:grid;grid-template-columns:repeat(auto-fill, 160px);justify-content:space-around;row-gap:15px;margin:15px 0}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden){display:block;position:relative;height:190px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted{background-color:rgba(0,0,0,0)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .fileactions{background-color:var(--color-background-hover)}.files-filestable.view-grid:not(.hidden) tbody td{display:inline;border-bottom:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper{min-width:0;max-width:none;position:absolute;width:160px;height:160px;padding:14px;top:0;left:0;z-index:-1}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail{width:calc(100% - 2 * 14px);height:calc(100% - 2 * 14px);background-size:contain;margin:0;border-radius:var(--border-radius);background-repeat:no-repeat;background-position:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail .favorite-mark{left:auto;top:-11px;right:-11px}.files-filestable.view-grid:not(.hidden) tbody td.filename .uploadtext{width:100%;margin:0;top:0;bottom:auto;height:28px;padding-top:4px;padding-left:28px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name{height:100%;border-radius:var(--border-radius);overflow:hidden;cursor:pointer !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext{display:flex;height:44px;margin-top:146px;text-align:center;line-height:44px;padding:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{display:inline-block;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:before{content:"";flex:1;min-width:14px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:after{content:"";flex:1;min-width:44px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .extension{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .system-tags{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions{height:initial;margin-top:146px;display:flex;align-items:center;position:absolute;right:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action{padding:14px;width:44px;height:44px;display:flex;align-items:center;justify-content:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action:not(.action-menu){display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden .action-share img{padding:6px;border-radius:50%}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-restore-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-comment-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename form{padding:3px 14px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody td.filename form input.filename{width:100%;margin-left:0;cursor:text}.files-filestable.view-grid:not(.hidden) tbody td.filesize,.files-filestable.view-grid:not(.hidden) tbody td.date{display:none}.files-filestable.view-grid:not(.hidden) tbody td.selection,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark{position:absolute;top:-8px;left:-8px;display:flex;z-index:10}.files-filestable.view-grid:not(.hidden) tbody td.selection label,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label{width:44px;height:44px;display:inline-flex;padding:14px}.files-filestable.view-grid:not(.hidden) tbody td.selection label::before,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label::before{margin:0;width:14px;height:14px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:0;width:150px;margin:0 5px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu .menuitem span:not(.icon){overflow:hidden;text-overflow:ellipsis}.files-filestable.view-grid:not(.hidden) tr.hidden-file td.filename .name .nametext .extension{display:block}.files-filestable.view-grid:not(.hidden) tfoot{display:grid}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden){display:inline-block;margin:0 auto;height:418px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td{padding-top:50px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td:first-child,.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td.date{display:none}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td .info{margin-left:0}#view-toggle{background-color:var(--color-main-background-translucent);border:none;margin:0;padding:22px;opacity:.5;float:right;right:var(--default-grid-baseline);top:var(--default-grid-baseline);z-index:100;position:sticky}#view-toggle:hover,#view-toggle:focus,#showgridview:focus+#view-toggle{opacity:1}#view-toggle:focus-visible,#showgridview:focus-visible+#view-toggle{box-shadow:inset 0 0 0 2px var(--color-primary-element) !important}#showgridview{position:fixed;top:0}#body-public .files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{max-width:124px}#body-public .files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:-80px}#body-public #view-toggle{position:absolute;right:0;top:0}#gallery-button{display:none}#tag_multiple_files_container{overflow:hidden;background-color:#fff;border-radius:3px;position:relative;display:flex;flex-wrap:wrap;margin-bottom:10px}#tag_multiple_files_container h3{width:100%;padding:0 18px}#tag_multiple_files_container .systemTagsInputFieldContainer{flex:1 1 80%;min-width:0;margin:0 12px}#upload{box-sizing:border-box;height:36px;width:39px;padding:0 !important;margin-left:3px;overflow:hidden;vertical-align:top;position:relative;z-index:-20}#upload .icon-upload{position:relative;display:block;width:100%;height:44px;width:44px;margin:-5px -3px;cursor:pointer;z-index:10;opacity:.65}.file_upload_target{display:none}.file_upload_form{display:inline;float:left;margin:0;padding:0;cursor:pointer;overflow:visible}.uploadprogresswrapper,.uploadprogresswrapper *{box-sizing:border-box}.uploadprogresswrapper{display:inline-block;vertical-align:top;height:36px;margin-left:3px}.uploadprogresswrapper>input[type=button]{height:36px;margin-left:3px}#uploadprogressbar{border-color:var(--color-border-dark);border-radius:var(--border-radius-pill) 0 0 var(--border-radius-pill);border-right:0;position:relative;float:left;width:200px;height:44px;display:inline-block;text-align:center}#uploadprogressbar .ui-progressbar-value{margin-top:.1em}#uploadprogressbar .ui-progressbar-value.ui-widget-header.ui-corner-left{height:calc(100% + 2px);top:-1px;left:-1px;position:absolute;overflow:hidden;background-color:var(--color-primary-element)}#uploadprogressbar .label{top:8px;opacity:1;overflow:hidden;white-space:nowrap;font-weight:normal}#uploadprogressbar .label.inner{color:var(--color-primary-element-text);position:absolute;display:block;width:200px}#uploadprogressbar .label.outer{position:relative;color:var(--color-main-text)}#uploadprogressbar .desktop{display:block}#uploadprogressbar .mobile{display:none}#uploadprogressbar+.stop{border-top-left-radius:0;border-bottom-left-radius:0}.oc-dialog .fileexists{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-bottom:30px}.oc-dialog .fileexists .conflict .filename,.oc-dialog .fileexists .conflict .mtime,.oc-dialog .fileexists .conflict .size{-webkit-touch-callout:initial;-webkit-user-select:initial;-khtml-user-select:initial;-moz-user-select:initial;-ms-user-select:initial;user-select:initial}.oc-dialog .fileexists .conflict .message{color:#e9322d}.oc-dialog .fileexists table{width:100%}.oc-dialog .fileexists th{padding-left:0;padding-right:0}.oc-dialog .fileexists th input[type=checkbox]{margin-right:3px}.oc-dialog .fileexists th:first-child{width:225px}.oc-dialog .fileexists th label{font-weight:normal;color:var(--color-main-text)}.oc-dialog .fileexists th .count{margin-left:3px}.oc-dialog .fileexists .conflicts .template{display:none}.oc-dialog .fileexists .conflict{width:100%;height:85px}.oc-dialog .fileexists .conflict .filename{color:#777;word-break:break-all;clear:left}.oc-dialog .fileexists .icon{width:64px;height:64px;margin:0px 5px 5px 5px;background-repeat:no-repeat;background-size:64px 64px;float:left}.oc-dialog .fileexists .original,.oc-dialog .fileexists .replacement{float:left;width:50%}.oc-dialog .fileexists .conflicts{overflow-y:auto;max-height:225px}.oc-dialog .fileexists .conflict input[type=checkbox]{float:left}.oc-dialog .fileexists #allfileslabel{float:right}.oc-dialog .fileexists #allfiles{vertical-align:bottom;position:relative;top:-3px}.oc-dialog .fileexists #allfiles+span{vertical-align:bottom}.oc-dialog .oc-dialog-buttonrow{width:100%;text-align:right}.oc-dialog .oc-dialog-buttonrow .cancel{float:left}.highlightUploaded{-webkit-animation:highlightAnimation 2s 1;-moz-animation:highlightAnimation 2s 1;-o-animation:highlightAnimation 2s 1;animation:highlightAnimation 2s 1}@-webkit-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@-moz-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@-o-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@media only screen and (max-width: 988px)and (min-width: 1025px),only screen and (max-width: 688px){.app-files #app-content.dir-drop{background-color:#fff !important}table th.column-size,table td.filesize,table th.column-mtime,table td.date{display:none}table td{padding:0}table.multiselect thead{padding-left:0}.fileList a.action.action-menu img{padding-left:0}.fileList .fileActionsMenu{margin-right:6px}.fileList a.action-share span:not(.icon):not(.avatar){position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}td.filename a.name .system-tags{display:none}#uploadprogressbar,#uploadprogressbar .label.inner{width:50px}#uploadprogressbar .desktop{display:none !important}#uploadprogressbar .mobile{display:block !important}table.dragshadow{z-index:1000}}@media only screen and (max-width: 480px){table th .selectedActions{float:right}table th .selectedActions>a span:not(.icon){display:none}table th .selectedActions a{padding:17px 14px}table.multiselect th .columntitle.name{margin-left:0}}.app-sidebar .detailFileInfoContainer{min-height:50px;padding:15px}.app-sidebar .detailFileInfoContainer>div{clear:both}.app-sidebar .mainFileInfoView .icon{display:inline-block;background-size:16px 16px}.app-sidebar .mainFileInfoView .permalink{padding:6px 10px;vertical-align:top;opacity:.6}.app-sidebar .mainFileInfoView .permalink:hover,.app-sidebar .mainFileInfoView .permalink:focus{opacity:1}.app-sidebar .mainFileInfoView .permalink-field>input{clear:both;width:90%}.app-sidebar .thumbnailContainer.large{margin-left:-15px;margin-right:-35px;margin-top:-15px}.app-sidebar .thumbnailContainer.large.portrait{margin:0}.app-sidebar .large .thumbnail{width:100%;display:block;background-repeat:no-repeat;background-position:center;background-size:100%;float:none;margin:0;height:auto}.app-sidebar .large .thumbnail .stretcher{content:"";display:block;padding-bottom:56.25%}.app-sidebar .large.portrait .thumbnail{background-position:50% top}.app-sidebar .large.portrait .thumbnail{background-size:contain}.app-sidebar .large.text{overflow-y:scroll;overflow-x:hidden;padding-top:14px;font-size:80%;margin-left:0}.app-sidebar .thumbnail{width:100%;min-height:75px;display:inline-block;float:left;margin-right:10px;background-size:contain;background-repeat:no-repeat}.app-sidebar .ellipsis{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.app-sidebar .fileName{font-size:16px;padding-top:13px;padding-bottom:3px}.app-sidebar .fileName h3{width:calc(100% - 42px);display:inline-block;padding:5px 0;margin:-5px 0}.app-sidebar .file-details{color:var(--color-text-maxcontrast)}.app-sidebar .action-favorite{vertical-align:sub;padding:10px;margin:-10px}.app-sidebar .action-favorite>span{opacity:.7 !important}.app-sidebar .detailList{float:left}.app-sidebar .close{position:absolute;top:0;right:0;opacity:.5;z-index:1;width:44px;height:44px}.whatsNewPopover{bottom:35px !important;left:15px !important;width:270px;z-index:700}.whatsNewPopover p{width:auto !important}.whatsNewPopover .caption{font-weight:bold;cursor:auto !important}.whatsNewPopover .icon-close{position:absolute;right:0}.whatsNewPopover::after{content:none}/*# sourceMappingURL=merged.css.map */ +.actions{padding:3px;height:100%;display:inline-block;float:left}.actions input,.actions button,.actions .button{margin:0;float:left}.actions .button a{color:#555}.actions .button a:hover,.actions .button a:focus{background-color:var(--color-background-hover)}.actions .button a:active{background-color:var(--color-primary-element-light)}.actions.creatable{position:relative;display:flex;flex:1 1}.actions.creatable .button:not(:last-child){margin-right:3px}.actions.hidden{display:none}#trash{margin-right:8px;float:right;z-index:1010;padding:10px;font-weight:normal}.newFileMenu .error,.newFileMenu .error+.icon-confirm,.files-fileList .error{color:var(--color-error);border-color:var(--color-error)}.files-filestable{position:relative;width:100%;min-width:250px;display:block;flex-direction:column}.emptycontent:not(.hidden)~.files-filestable{display:none}.files-filestable thead{position:-webkit-sticky;position:sticky;top:44px;z-index:60;display:block;background-color:var(--color-main-background-translucent)}.files-filestable tbody{display:table;width:100%}.files-filestable tbody tr[data-permissions="0"],.files-filestable tbody tr[data-permissions="16"]{background-color:var(--color-background-dark)}.files-filestable tbody tr[data-permissions="0"] td.filename .nametext .innernametext,.files-filestable tbody tr[data-permissions="16"] td.filename .nametext .innernametext{color:var(--color-text-maxcontrast)}.files-filestable tbody tr[data-e2eencrypted=true] .selection{pointer-events:none}.files-filestable.hidden{display:none}.app-files #app-content>.viewcontainer{min-height:0%;width:100%}.app-files #app-content{width:calc(100% - 300px);overflow-anchor:none}.file-drag,.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:var(--color-primary-element-light) !important}.app-files #app-content.dir-drop{background-color:var(--color-main-background) !important}.file-drag .files-filestable tbody tr,.file-drag .files-filestable tbody tr:hover{background-color:rgba(0,0,0,0) !important}.app-files #app-content.dir-drop .files-filestable tbody tr.dropping-to-dir{background-color:var(--color-primary-element-light) !important}.nav-icon-files{background-image:var(--icon-folder-dark)}.nav-icon-recent{background-image:var(--icon-recent-dark)}.nav-icon-favorites{background-image:var(--icon-starred-dark)}.nav-icon-sharinginOld,.nav-icon-sharingoutOld,.nav-icon-pendingsharesOld,.nav-icon-shareoverviewOld{background-image:var(--icon-share-dark)}.nav-icon-sharinglinksOld{background-image:var(--icon-public-dark)}.nav-icon-extstoragemounts{background-image:var(--icon-external-dark)}.nav-icon-trashbin{background-image:var(--icon-delete-dark)}.nav-icon-trashbin-starred{background-image:var(--icon-delete-#ff0000)}.nav-icon-deletedsharesOld{background-image:var(--icon-unshare-dark)}.nav-icon-favorites-starred{background-image:var(--icon-starred-yellow)}#app-navigation .nav-files a.nav-icon-files{width:auto}#app-navigation .nav-files a.new{width:40px;height:32px;padding:0 10px;margin:0;cursor:pointer}#app-navigation .nav-files a.new.hidden{display:none}#app-navigation .nav-files a.new.disabled{opacity:.3}.files-filestable tbody tr{height:51px}.files-filestable tbody tr:hover,.files-filestable tbody tr:focus,.files-filestable tbody .name:focus,.files-filestable tbody tr:hover .filename form,table tr.mouseOver td{background-color:var(--color-background-hover)}.files-filestable tbody tr:active,.files-filestable tbody tr.highlighted,.files-filestable tbody tr.highlighted .name:focus,.files-filestable tbody tr.selected,.files-filestable tbody tr.searchresult{background-color:var(--color-primary-element-light)}tbody a{color:var(--color-main-text)}span.conflict-path,span.extension,span.uploading,td.date{color:var(--color-text-maxcontrast)}span.conflict-path,span.extension{-webkit-transition:opacity 300ms;-moz-transition:opacity 300ms;-o-transition:opacity 300ms;transition:opacity 300ms;vertical-align:top}tr:hover span.conflict-path,tr:focus span.conflict-path,tr:hover span.extension,tr:focus span.extension{opacity:1;color:var(--color-text-maxcontrast)}table th,table th a{color:var(--color-text-maxcontrast)}table.multiselect th a{color:var(--color-main-text)}table th .columntitle{display:block;padding:15px;height:50px;box-sizing:border-box;-moz-box-sizing:border-box;vertical-align:middle}table th .columntitle:focus-visible{border-radius:2px}table.multiselect th .columntitle{display:inline-block;margin-right:-20px}table th .columntitle.name{padding-left:0;margin-left:44px}table.multiselect th .columntitle.name{margin-left:0}table th .sort-indicator{width:10px;height:8px;margin-left:5px;display:inline-block;vertical-align:text-bottom;opacity:.3}.sort-indicator.hidden,.multiselect .sort-indicator,table.multiselect th:hover .sort-indicator.hidden,table.multiselect th:focus .sort-indicator.hidden{visibility:hidden}.multiselect .sort,.multiselect .sort span{cursor:default}table th:hover .sort-indicator.hidden,table th:focus .sort-indicator.hidden{visibility:visible}table th,table td{border-bottom:1px solid var(--color-border);text-align:left;font-weight:normal}table td{padding:0 15px;font-style:normal;background-position:8px center;background-repeat:no-repeat}table th.column-name{position:relative;width:9999px;padding:0}.column-name-container{position:relative;height:50px}table th.column-selection{padding-top:2px}table th.column-size,table td.filesize{text-align:right}table th.column-mtime,table td.date,table th.column-last,table td.column-last{-moz-box-sizing:border-box;box-sizing:border-box;position:relative;min-width:130px}#app-content-recent,#app-content-favorites,#app-content-shareoverview,#app-content-sharingout,#app-content-sharingin,#app-content-sharinglinks,#app-content-deletedshares,#app-content-pendingshares{margin-top:22px}#app-content-recent thead,#app-content-favorites thead,#app-content-shareoverview thead,#app-content-sharingout thead,#app-content-sharingin thead,#app-content-sharinglinks thead,#app-content-deletedshares thead,#app-content-pendingshares thead{top:0}table.multiselect thead th{background-color:var(--color-main-background-translucent);font-weight:bold}#app-content.with-app-sidebar table.multiselect thead{margin-right:27%}table.multiselect .column-name{position:relative;width:9999px}table.multiselect .column-mtime>a{display:none}table td.selection,table th.selection,table td.fileaction{width:32px;text-align:center}table td.filename a.name,table td.filename p.name{display:flex;position:relative;-moz-box-sizing:border-box;box-sizing:border-box;height:50px;line-height:50px;padding:0}table td.filename .thumbnail-wrapper{width:0;min-width:50px;max-width:50px;height:50px}table td.filename .thumbnail-wrapper.icon-loading-small:after{z-index:10}table td.filename .thumbnail-wrapper.icon-loading-small .thumbnail{opacity:.2}table td.filename .thumbnail{display:inline-block;width:32px;height:32px;background-size:contain;background-position:center;background-repeat:no-repeat;margin-left:9px;margin-top:9px;border-radius:var(--border-radius);cursor:pointer;position:absolute;z-index:4}table td.filename p.name .thumbnail{cursor:default}table tr[data-has-preview=true] .thumbnail{border:1px solid var(--color-border)}table:not(.view-grid) td.filename input.filename{width:70% !important;margin-left:48px !important;cursor:text}table td.filename form{margin-top:-40px;position:relative;top:-6px}table td.filename a,table td.login,table td.logout,table td.download,table td.upload,table td.create,table td.delete{padding:3px 8px 8px 3px}table td.filename .nametext,.modified,.column-last>span:first-child{float:left;padding:15px 0}.modified,.column-last>span:first-child{position:relative;overflow:hidden;text-overflow:ellipsis;width:110px}table td.filename{max-width:0}table td.filename .nametext{width:0;flex-grow:1;display:flex;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;height:100%;z-index:10;padding:0 20px 0 0}table td.filename .system-tags{--min-size: 32px;display:flex;justify-content:center;align-items:center;min-width:calc(var(--min-size)*2);max-width:300px}table td.filename .system-tags .system-tags__tag{padding:5px 10px;border:1px solid;border-radius:var(--border-radius-pill);border-color:var(--color-border);color:var(--color-text-maxcontrast);height:var(--min-size);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:22px;text-align:center}table td.filename .system-tags .system-tags__tag--more{overflow:visible;text-overflow:initial}table td.filename .system-tags .system-tags__tag+.system-tags__tag{margin-left:5px}.hide-hidden-files .files-filestable .files-fileList tr.hidden-file,.hide-hidden-files .files-filestable .files-fileList tr.hidden-file.dragging{display:none !important}.files-fileList tr.animate-opacity{-webkit-transition:opacity 250ms;-moz-transition:opacity 250ms;-o-transition:opacity 250ms;transition:opacity 250ms}.files-fileList tr.dragging{opacity:.2}table td.filename .nametext .innernametext{text-overflow:ellipsis;overflow:hidden;position:relative;vertical-align:top}table td.filename .uploadtext{position:absolute;font-weight:normal;margin-left:50px;left:0;bottom:0;height:20px;padding:0 4px;padding-left:1px;font-size:11px;line-height:22px;color:var(--color-text-maxcontrast);text-overflow:ellipsis;white-space:nowrap}table td.selection{padding:0}.files-fileList tr td.selection>.selectCheckBox+label:before{opacity:.3;margin-right:0}.files-fileList tr:hover td.selection>.selectCheckBox+label:before,.files-fileList tr:focus td.selection>.selectCheckBox+label:before,.files-fileList tr td.selection>.selectCheckBox:checked+label:before,.files-fileList tr.selected td.selection>.selectCheckBox+label:before{opacity:1}.files-fileList tr.halfselected td.selection>.selectCheckBox+label:before{opacity:.5}.files-fileList tr td.selection>.selectCheckBox+label,.select-all+label{padding:16px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill);outline:none !important;border:2px solid var(--color-primary-element) !important;padding:14px}.files-fileList tr td.selection>.selectCheckBox:focus-visible+label,.select-all:focus-visible+label{outline-offset:0px}.files-fileList tr td.filename{position:relative;width:100%;padding-left:0;padding-right:0;-webkit-transition:background-image 500ms;-moz-transition:background-image 500ms;-o-transition:background-image 500ms;transition:background-image 500ms}.files-fileList tr td.filename a.name label,.files-fileList tr td.filename p.name label{position:absolute;width:80%;height:50px}.files-fileList tr td.filename .favorite{display:inline-block;float:left}.files-fileList tr td.filename .favorite-mark{position:absolute;display:block;top:-8px;right:-8px;line-height:100%;text-align:center}.files-fileList tr td.filename .favorite-mark.permanent{background-color:var(--color-main-background);mask:var(--icon-star-rounded-white) no-repeat;mask-size:22px 22px;width:22px;height:22px;display:flex;align-content:center;justify-content:center}.files-fileList tr:hover td.filename .favorite-mark.permanent{background-color:var(--color-background-hover)}#uploadsize-message,#delete-confirm{display:none}.fileactions{z-index:50}.busy .fileactions,.busy .action{visibility:hidden}.bubble,#app-navigation .app-navigation-entry-menu{min-width:100px}.files-fileList .icon-loading-small{opacity:1 !important;display:inline !important}.files-fileList .action.action-share-notification span,.files-fileList a.name{cursor:default !important}.files-fileList a.name.disabled *{cursor:default}.files-fileList a.name.disabled a,.files-fileList a.name.disabled a *{cursor:pointer}.files-fileList a.name.disabled:focus{background:none}a.action>img{height:16px;width:16px;vertical-align:text-bottom}a.action.action-editlocally img.icon{filter:var(--background-invert-if-dark)}.selectedActions{position:relative;display:inline-block;vertical-align:middle}.selectedActions.hidden{display:none}.selectedActions a{display:inline;line-height:50px;padding:16px 5px}.selectedActions a.hidden{display:none}.selectedActions a img{position:relative;vertical-align:text-bottom;margin-bottom:-1px}.selectedActions .actions-selected .icon-more{margin-top:-3px}.files-fileList td a a.action{display:inline;padding:17px 8px;line-height:50px;opacity:.3}.files-fileList td a a.action.action-share{padding:17px 14px}.files-fileList td a a.action.action-share.permanent:not(.shared-style) .icon-shared+span{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}.files-fileList td a a.action.action-share .avatar{display:inline-block;vertical-align:middle}.files-fileList td a a.action.action-menu{padding-top:17px;padding-bottom:17px;padding-left:14px;padding-right:14px}.files-fileList td a a.action.no-permission:hover,.files-fileList td a a.action.no-permission:focus{opacity:.3}.files-fileList td a a.action.disabled:hover,.files-fileList td a a.action.disabled:focus,.files-fileList td a a.action.disabled img{opacity:.3}.files-fileList td a a.action.disabled.action-download{opacity:.7}.files-fileList td a a.action.disabled.action-download:hover,.files-fileList td a a.action.disabled.action-download:focus{opacity:.7}.files-fileList td a a.action:hover,.files-fileList td a a.action:focus{opacity:1}.files-fileList td a a.action:focus{background-color:var(--color-background-hover);border-radius:var(--border-radius-pill)}.files-fileList td a .fileActionsMenu a.action,.files-fileList td a a.action.action-share.shared-style{opacity:.7}.files-fileList td a .fileActionsMenu .action.permanent{opacity:1}.files-fileList .action.action-share.permanent.shared-style span:not(.icon){display:inline-block;max-width:70px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;margin-left:6px}.files-fileList .remoteAddress .userDomain{margin-left:0 !important}.files-fileList .favorite-mark.permanent{opacity:1}.files-fileList .fileActionsMenu a.action:hover,.files-fileList .fileActionsMenu a.action:focus,.files-fileList a.action.action-share.shared-style:hover,.files-fileList a.action.action-share.shared-style:focus{opacity:1}.files-fileList tr a.action.disabled{background:none}.selectedActions a.download.disabled,.files-fileList tr a.action.action-download.disabled{color:#000}.files-fileList tr:hover a.action.disabled:hover *{cursor:default}.summary{color:var(--color-text-maxcontrast);height:330px}.files-filestable .summary .filesummary{width:100%;padding-left:101px}#body-public .summary{height:180px}.summary:hover,.summary:focus,.summary,table tr.summary td{background-color:rgba(0,0,0,0)}.summary td{border-bottom:none;vertical-align:top;padding-top:20px}.summary td:first-child{padding:0}.hiddeninfo{white-space:pre-line}table.dragshadow{width:auto;z-index:2000}table.dragshadow td.filename{padding-left:60px;padding-right:16px;height:36px;max-width:unset}table.dragshadow td.size{padding-right:8px}.mask{z-index:50;position:absolute;top:0;left:0;right:0;bottom:0;background-color:var(--color-main-background);background-repeat:no-repeat no-repeat;background-position:50%;opacity:.7;transition:opacity 100ms;-moz-transition:opacity 100ms;-o-transition:opacity 100ms;-ms-transition:opacity 100ms;-webkit-transition:opacity 100ms}.mask.transparent{opacity:0}.newFileMenu{font-weight:300;top:100%;left:-48px !important;margin-top:4px;min-width:100px;z-index:1001}.newFileMenu::after{left:61px !important}.files-controls{box-sizing:border-box;position:-webkit-sticky;position:sticky;height:50px;padding:0;margin:0;background-color:var(--color-main-background-translucent);z-index:62;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;top:0;padding-left:50px}.files-controls .actions>div>.button,.files-controls .actions>div button,.files-controls .actions>.button,.files-controls .actions button{box-sizing:border-box;display:inline-block;display:flex;height:44px;width:44px;padding:9px;align-items:center;justify-content:center}.files-controls .actions>div .button.hidden,.files-controls .actions .button.hidden{display:none}.viewer-mode #app-navigation+#app-content .files-controls{left:0}.files-filestable .filename .action .icon,.files-filestable .selectedActions a .icon,.files-filestable .filename .favorite-mark .icon,.files-controls .actions .button .icon{display:inline-block;vertical-align:middle;background-size:16px 16px}.files-filestable .filename .favorite-mark .icon-star{background-image:none}.files-filestable .filename .favorite-mark .icon-starred{background-image:var(--icon-starred-yellow) !important}.files-filestable .filename .action .icon.hidden,.files-filestable .selectedActions a .icon.hidden,.files-controls .actions .button .icon.hidden{display:none}.files-filestable .filename .action .icon.loading,.files-filestable .selectedActions a .icon.loading,.files-controls .actions .button .icon.loading{width:15px;height:15px}.app-files .actions .button.new{position:relative}.breadcrumb{align-items:center}.breadcrumb .icon-home{border-radius:var(--border-radius)}.breadcrumb .canDrop>a,.files-filestable tbody tr.canDrop{background-color:rgba(0,130,201,.3)}.dropzone-background{background-color:rgba(0,130,201,.3)}.dropzone-background :hover{box-shadow:none !important}.notCreatable{margin-left:12px;margin-right:44px;margin-top:12px;color:var(--color-main-text);overflow:auto;min-width:160px;height:54px}.notCreatable:not(.hidden){display:flex}.notCreatable .icon-alert-outline{top:-15px;position:relative;margin-right:4px}.quota-navigation-item{margin:0 !important;border:none;border-radius:0;background-color:rgba(0,0,0,0);z-index:1;height:44px;display:flex !important;flex-direction:column}.quota-navigation-item__text{height:30px}.quota-navigation-item[href="#"],.quota-navigation-item[href="#"] *{cursor:default !important}.quota-navigation-item__container{height:5px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) thead tr{display:block;border-bottom:1px solid var(--color-border);background-color:var(--color-main-background-translucent)}.files-filestable.view-grid:not(.hidden) thead tr th{width:auto;border:none}.files-filestable.view-grid:not(.hidden) tbody{display:grid;grid-template-columns:repeat(auto-fill, 160px);justify-content:space-around;row-gap:15px;margin:15px 0}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden){display:block;position:relative;height:190px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted{background-color:rgba(0,0,0,0)}.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):hover .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden):active .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).selected .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).searchresult .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden) .name:focus .fileactions,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .thumbnail-wrapper,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .nametext,.files-filestable.view-grid:not(.hidden) tbody tr:not(.hidden).highlighted .fileactions{background-color:var(--color-background-hover)}.files-filestable.view-grid:not(.hidden) tbody td{display:inline;border-bottom:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper{min-width:0;max-width:none;position:absolute;width:160px;height:160px;padding:14px;top:0;left:0;z-index:-1}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail{width:calc(100% - 2 * 14px);height:calc(100% - 2 * 14px);background-size:contain;margin:0;border-radius:var(--border-radius);background-repeat:no-repeat;background-position:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .thumbnail-wrapper .thumbnail .favorite-mark{left:auto;top:-11px;right:-11px}.files-filestable.view-grid:not(.hidden) tbody td.filename .uploadtext{width:100%;margin:0;top:0;bottom:auto;height:28px;padding-top:4px;padding-left:28px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name{height:100%;border-radius:var(--border-radius);overflow:hidden;cursor:pointer !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext{display:flex;height:44px;margin-top:146px;text-align:center;line-height:44px;padding:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{display:inline-block;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:before{content:"";flex:1;min-width:14px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext:after{content:"";flex:1;min-width:44px}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .extension{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .system-tags{display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions{height:initial;margin-top:146px;display:flex;align-items:center;position:absolute;right:0}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action{padding:14px;width:44px;height:44px;display:flex;align-items:center;justify-content:center}.files-filestable.view-grid:not(.hidden) tbody td.filename .name .fileactions .action:not(.action-menu){display:none}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-share-container.hidden .action-share img{padding:6px;border-radius:50%}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-restore-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename .fileActionsMenu .action-comment-container.hidden{display:block !important}.files-filestable.view-grid:not(.hidden) tbody td.filename form{padding:3px 14px;border-radius:var(--border-radius)}.files-filestable.view-grid:not(.hidden) tbody td.filename form input.filename{width:100%;margin-left:0;cursor:text}.files-filestable.view-grid:not(.hidden) tbody td.filesize,.files-filestable.view-grid:not(.hidden) tbody td.date{display:none}.files-filestable.view-grid:not(.hidden) tbody td.selection,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark{position:absolute;top:-8px;left:-8px;display:flex;z-index:10}.files-filestable.view-grid:not(.hidden) tbody td.selection label,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label{width:44px;height:44px;display:inline-flex;padding:14px}.files-filestable.view-grid:not(.hidden) tbody td.selection label::before,.files-filestable.view-grid:not(.hidden) tbody td.filename .favorite-mark label::before{margin:0;width:14px;height:14px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:0;width:150px;margin:0 5px}.files-filestable.view-grid:not(.hidden) tbody td .popovermenu .menuitem span:not(.icon){overflow:hidden;text-overflow:ellipsis}.files-filestable.view-grid:not(.hidden) tr.hidden-file td.filename .name .nametext .extension{display:block}.files-filestable.view-grid:not(.hidden) tfoot{display:grid}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden){display:inline-block;margin:0 auto;height:418px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td{padding-top:50px}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td:first-child,.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td.date{display:none}.files-filestable.view-grid:not(.hidden) tfoot .summary:not(.hidden) td .info{margin-left:0}#view-toggle{background-color:var(--color-main-background-translucent);border:none;margin:0;padding:22px;opacity:.5;float:right;right:var(--default-grid-baseline);top:var(--default-grid-baseline);z-index:100;position:sticky}#view-toggle:hover,#view-toggle:focus,#showgridview:focus+#view-toggle{opacity:1}#view-toggle:focus-visible,#showgridview:focus-visible+#view-toggle{box-shadow:inset 0 0 0 2px var(--color-primary-element) !important}#showgridview{position:fixed;top:0}#body-public .files-filestable.view-grid:not(.hidden) tbody td.filename .name .nametext .innernametext{max-width:124px}#body-public .files-filestable.view-grid:not(.hidden) tbody td .popovermenu{left:-80px}#body-public #view-toggle{position:absolute;right:0;top:0}#gallery-button{display:none}#tag_multiple_files_container{overflow:hidden;background-color:#fff;border-radius:3px;position:relative;display:flex;flex-wrap:wrap;margin-bottom:10px}#tag_multiple_files_container h3{width:100%;padding:0 18px}#tag_multiple_files_container .systemTagsInputFieldContainer{flex:1 1 80%;min-width:0;margin:0 12px}#upload{box-sizing:border-box;height:36px;width:39px;padding:0 !important;margin-left:3px;overflow:hidden;vertical-align:top;position:relative;z-index:-20}#upload .icon-upload{position:relative;display:block;width:100%;height:44px;width:44px;margin:-5px -3px;cursor:pointer;z-index:10;opacity:.65}.file_upload_target{display:none}.file_upload_form{display:inline;float:left;margin:0;padding:0;cursor:pointer;overflow:visible}.uploadprogresswrapper,.uploadprogresswrapper *{box-sizing:border-box}.uploadprogresswrapper{display:inline-block;vertical-align:top;height:36px;margin-left:3px}.uploadprogresswrapper>input[type=button]{height:36px;margin-left:3px}#uploadprogressbar{border-color:var(--color-border-dark);border-radius:var(--border-radius-pill) 0 0 var(--border-radius-pill);border-right:0;position:relative;float:left;width:200px;height:44px;display:inline-block;text-align:center}#uploadprogressbar .ui-progressbar-value{margin-top:.1em}#uploadprogressbar .ui-progressbar-value.ui-widget-header.ui-corner-left{height:calc(100% + 2px);top:-1px;left:-1px;position:absolute;overflow:hidden;background-color:var(--color-primary-element)}#uploadprogressbar .label{top:8px;opacity:1;overflow:hidden;white-space:nowrap;font-weight:normal}#uploadprogressbar .label.inner{color:var(--color-primary-element-text);position:absolute;display:block;width:200px}#uploadprogressbar .label.outer{position:relative;color:var(--color-main-text)}#uploadprogressbar .desktop{display:block}#uploadprogressbar .mobile{display:none}#uploadprogressbar+.stop{border-top-left-radius:0;border-bottom-left-radius:0}.oc-dialog .fileexists{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-bottom:30px}.oc-dialog .fileexists .conflict .filename,.oc-dialog .fileexists .conflict .mtime,.oc-dialog .fileexists .conflict .size{-webkit-touch-callout:initial;-webkit-user-select:initial;-khtml-user-select:initial;-moz-user-select:initial;-ms-user-select:initial;user-select:initial}.oc-dialog .fileexists .conflict .message{color:#e9322d}.oc-dialog .fileexists table{width:100%}.oc-dialog .fileexists th{padding-left:0;padding-right:0}.oc-dialog .fileexists th input[type=checkbox]{margin-right:3px}.oc-dialog .fileexists th:first-child{width:225px}.oc-dialog .fileexists th label{font-weight:normal;color:var(--color-main-text)}.oc-dialog .fileexists th .count{margin-left:3px}.oc-dialog .fileexists .conflicts .template{display:none}.oc-dialog .fileexists .conflict{width:100%;height:85px}.oc-dialog .fileexists .conflict .filename{color:#777;word-break:break-all;clear:left}.oc-dialog .fileexists .icon{width:64px;height:64px;margin:0px 5px 5px 5px;background-repeat:no-repeat;background-size:64px 64px;float:left}.oc-dialog .fileexists .original,.oc-dialog .fileexists .replacement{float:left;width:50%}.oc-dialog .fileexists .conflicts{overflow-y:auto;max-height:225px}.oc-dialog .fileexists .conflict input[type=checkbox]{float:left}.oc-dialog .fileexists #allfileslabel{float:right}.oc-dialog .fileexists #allfiles{vertical-align:bottom;position:relative;top:-3px}.oc-dialog .fileexists #allfiles+span{vertical-align:bottom}.oc-dialog .oc-dialog-buttonrow{width:100%;text-align:right}.oc-dialog .oc-dialog-buttonrow .cancel{float:left}.highlightUploaded{-webkit-animation:highlightAnimation 2s 1;-moz-animation:highlightAnimation 2s 1;-o-animation:highlightAnimation 2s 1;animation:highlightAnimation 2s 1}@-webkit-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@-moz-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@-o-keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@keyframes highlightAnimation{0%{background-color:#ffff8c}100%{background-color:rgba(0,0,0,0)}}@media only screen and (max-width: 988px)and (min-width: 1025px),only screen and (max-width: 688px){.app-files #app-content.dir-drop{background-color:#fff !important}table th.column-size,table td.filesize,table th.column-mtime,table td.date{display:none}table td{padding:0}table.multiselect thead{padding-left:0}.fileList a.action.action-menu img{padding-left:0}.fileList .fileActionsMenu{margin-right:6px}.fileList a.action-share span:not(.icon):not(.avatar){position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}td.filename a.name .system-tags{display:none}#uploadprogressbar,#uploadprogressbar .label.inner{width:50px}#uploadprogressbar .desktop{display:none !important}#uploadprogressbar .mobile{display:block !important}table.dragshadow{z-index:1000}}@media only screen and (max-width: 480px){table th .selectedActions{float:right}table th .selectedActions>a span:not(.icon){display:none}table th .selectedActions a{padding:17px 14px}table.multiselect th .columntitle.name{margin-left:0}}.app-sidebar .detailFileInfoContainer{min-height:50px;padding:15px}.app-sidebar .detailFileInfoContainer>div{clear:both}.app-sidebar .mainFileInfoView .icon{display:inline-block;background-size:16px 16px}.app-sidebar .mainFileInfoView .permalink{padding:6px 10px;vertical-align:top;opacity:.6}.app-sidebar .mainFileInfoView .permalink:hover,.app-sidebar .mainFileInfoView .permalink:focus{opacity:1}.app-sidebar .mainFileInfoView .permalink-field>input{clear:both;width:90%}.app-sidebar .thumbnailContainer.large{margin-left:-15px;margin-right:-35px;margin-top:-15px}.app-sidebar .thumbnailContainer.large.portrait{margin:0}.app-sidebar .large .thumbnail{width:100%;display:block;background-repeat:no-repeat;background-position:center;background-size:100%;float:none;margin:0;height:auto}.app-sidebar .large .thumbnail .stretcher{content:"";display:block;padding-bottom:56.25%}.app-sidebar .large.portrait .thumbnail{background-position:50% top}.app-sidebar .large.portrait .thumbnail{background-size:contain}.app-sidebar .large.text{overflow-y:scroll;overflow-x:hidden;padding-top:14px;font-size:80%;margin-left:0}.app-sidebar .thumbnail{width:100%;min-height:75px;display:inline-block;float:left;margin-right:10px;background-size:contain;background-repeat:no-repeat}.app-sidebar .ellipsis{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.app-sidebar .fileName{font-size:16px;padding-top:13px;padding-bottom:3px}.app-sidebar .fileName h3{width:calc(100% - 42px);display:inline-block;padding:5px 0;margin:-5px 0}.app-sidebar .file-details{color:var(--color-text-maxcontrast)}.app-sidebar .action-favorite{vertical-align:sub;padding:10px;margin:-10px}.app-sidebar .action-favorite>span{opacity:.7 !important}.app-sidebar .detailList{float:left}.app-sidebar .close{position:absolute;top:0;right:0;opacity:.5;z-index:1;width:44px;height:44px}.whatsNewPopover{bottom:35px !important;left:15px !important;width:270px;z-index:700}.whatsNewPopover p{width:auto !important}.whatsNewPopover .caption{font-weight:bold;cursor:auto !important}.whatsNewPopover .icon-close{position:absolute;right:0}.whatsNewPopover::after{content:none}/*# sourceMappingURL=merged.css.map */ diff --git a/apps/files/css/merged.css.map b/apps/files/css/merged.css.map index 06281821a75..231053d13a8 100644 --- a/apps/files/css/merged.css.map +++ b/apps/files/css/merged.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["files.scss","../../../core/css/functions.scss","upload.scss","mobile.scss","detailsView.scss","../../../core/css/whatsnew.scss"],"names":[],"mappings":"AAWA,SAEC,YACA,YACA,qBACA,WAED,oEACA,8BACA,kDAEC,+CAED,0BACC,oDAGD,mBACC,kBACA,aACA,SACA,4CACC,iBAIF,gBACC,aAGD,OACC,iBACA,YACA,aACA,aACA,mBAGD,6EAGC,yBACA,gCAID,kBACC,kBACA,WACA,gBACA,cACA,sBAEA,6CACC,aAGD,wBACC,wBACA,gBAEA,SAEA,WACA,cACA,0DAMD,wBACC,cACA,WAEA,mGAEC,8CAEA,6KACC,oCAKF,8DACC,oBAKH,yBACC,aAID,uCACC,cACA,WAGD,wBAGC,yBAEA,qBAGD,6FACC,+DAGD,iCACC,yDAGD,kFACC,0CAGD,4EACC,+DAID,gBCxEC,yCD2ED,iBC3EC,yCD8ED,oBC9EC,0CDiFD,yFCjFC,wCDuFD,uBCvFC,yCD0FD,2BC1FC,2CD6FD,mBC7FC,yCDgGD,2BChGC,4CDmGD,wBCnGC,0CDsGD,4BCtGC,4CD0GD,4CACC,WAGD,iCACC,WACA,YACA,eACA,SACA,eAGD,wCACC,aAGD,0CACC,WAGD,2BACC,YAED,4KAKC,+CAED,wMAKC,oDAGD,qCAEA,yDACC,oCAED,kCACC,iCACA,8BACA,4BACA,yBACA,mBAED,wGAIC,UACA,oCAGD,oBACC,oCAED,uBACC,6BAED,sBACC,cACA,aACA,YACA,sBACA,2BACA,sBACA,oCACC,kBAGF,kCACC,qBACA,mBAED,2BACC,eACA,iBAGD,uCACC,cAGD,yBACC,WACA,WACA,gBACA,qBACA,2BACA,WAED,wJAIC,kBAED,2CACC,eAED,4EAEC,mBAGD,kBAEC,4CACA,gBACA,mBAED,SACC,eACA,kBACA,+BACA,4BAED,qBACC,kBACA,aACA,UAGD,uBACC,kBACA,YAGD,0BACC,gBAED,uCACC,iBAED,8EAEC,2BACA,sBACA,kBAEA,gBAGD,qMAQC,gBACA,qPACC,MAIF,2BACC,0DACA,iBAGD,sDACC,iBAGD,+BACC,kBACA,aAED,kCACC,aAGD,0DAGC,WACA,kBAED,kDAEC,aACA,kBACA,2BACA,sBACA,YACA,iBACA,UAED,qCAEC,QACA,eACA,eACA,YAGA,8DACC,WAED,mEACC,WAGF,6BACC,qBACA,WACA,YACA,wBACA,2BACA,4BACA,gBACA,eACA,mCACA,eACA,kBACA,UAED,oCACC,eAID,2CACC,qCAGD,iDACC,qBACA,4BACA,YAED,uBACC,iBACA,kBACA,SAGD,6IACA,8FAEA,wCACC,kBACA,gBACA,uBACA,YAKA,kBACC,YACA,4BACC,QACA,YACA,aACA,gBACA,mBACA,uBACA,YACA,WACA,mBAID,+BACC,iBACA,aACA,uBACA,mBACA,kCACA,gBAEA,iDACC,iBACA,iBACA,wCACA,iCACA,oCACA,uBACA,mBACA,gBACA,uBACA,iBACA,kBAEA,uDACC,iBACA,sBAID,mEACC,gBAOL,iJAEC,wBAGD,mCACC,iCACA,8BACA,4BACA,yBAED,4BACC,WAGD,2CACC,uBACA,gBACA,kBACA,mBAKD,8BACC,kBACA,mBAEA,iBACA,OACA,SACA,YACA,cAEA,iBACA,eAEA,iBACA,oCACA,uBACA,mBAGD,mBACC,UAID,6DACC,WACA,eAID,iRAIC,UAID,0EACC,WAMA,wEACC,aAGD,oGACC,+CACA,wCACA,wBACA,yDACA,aAIF,oGAEC,mBAGD,+BACC,kBACA,WACA,eACA,gBACA,wJAGD,wFAEC,kBACA,UACA,YAGD,yCACC,qBACA,WAED,8CACC,kBACA,cACA,SACA,WACA,iBACA,kBACA,wDAEC,8CACA,8CACA,oBAEA,WACA,YACA,aACA,qBACA,uBAGF,8DACC,+CAGD,iDAGA,aACC,WAGD,iCACC,kBAID,mDAEC,gBAID,oCACC,qBACA,0BAGD,8EACC,0BAOA,kCACC,eAGD,sEACC,eAGD,sCACC,gBAIF,aACC,YACA,WACA,2BAGD,qCACC,wCAID,iBACI,kBACA,qBACA,sBAEJ,wBACI,aAEJ,mBACC,eACA,iBACA,iBAGD,0BACC,aAED,uBACC,kBACA,2BACA,mBAGD,8CACC,gBAIA,8BACC,eACA,iBACA,iBACA,WACA,2CACC,kBACA,0FAGC,kBACA,cACA,SACA,UACA,WACA,gBAED,mDACC,qBACA,sBAGF,0CACC,iBACA,oBACA,kBACA,mBAGA,oGACC,WAID,qIAEC,WAED,uDACC,WACA,0HACC,WAIH,wEACC,UAED,oCACC,+CACA,wCAGF,uGACC,WAED,wDACC,UAKF,4EACC,qBACA,eACA,gBACA,uBACA,sBACA,gBAGD,2CACC,yBAGD,yCACC,UAGD,kNAKC,UAGD,qCACC,gBAGD,0FAEC,WAGD,mDACC,eAGD,SACC,oCAGA,aAED,wCACC,WAEA,mBAKD,sBACC,aAED,2DAIC,+BAED,YACC,mBACA,mBACA,iBAED,wBACC,UAED,YACC,qBAGD,iBACC,WACA,aAED,6BACC,kBACA,mBACA,YAGA,gBAED,yBACC,kBAED,MACC,WACA,kBACA,MACA,OACA,QACA,SACA,8CACA,sCACA,wBACA,WACA,yBACA,8BACA,4BACA,6BACA,iCAED,kBACC,UAGD,aACC,gBACA,SACA,sBACA,eACA,gBACA,aAGA,oBACC,qBAKF,gBACC,sBACA,wBACA,gBACA,YACA,UACA,SACA,0DACA,WACA,yBACA,sBACA,qBACA,iBACA,aACA,MACA,kBAKE,0IACC,sBACA,qBACA,aACA,YACA,WACA,YACA,mBACA,uBAED,oFACC,aAQJ,0DACC,OAGD,6KAIC,qBACA,sBACA,0BAMA,sDACC,sBAED,yDACC,uDAIF,iJAGC,aAGD,oJAGC,WACA,YAGD,gCACC,kBAGD,YACC,mBAEA,uBACC,mCAIF,0DAEC,oCAED,qBACC,oCACA,4BACC,2BAIF,cACC,iBACA,kBACA,gBACA,6BACA,cACA,gBACA,YAEA,2BACC,aAGD,kCACC,UACA,kBACA,iBAIF,uBACC,oBACA,YACA,gBACA,+BACA,UACA,YACA,wBACA,sBAEA,6BACC,YAKA,oEACC,0BAIF,kCACC,WACA,mCAWA,kDACC,cACA,4CACA,0DACA,qDACC,WACA,YAMH,+CACC,aACA,+CACA,6BACA,aACA,cAGA,+DACC,cACA,kBACA,aACA,mCAEA,0fAKC,+BAEA,oxDAGC,+CAKH,kDACC,eACA,mBAGC,8EACC,YACA,eACA,kBACA,MAvDQ,MAwDR,OAxDQ,MAyDR,QAxDO,KAyDP,MACA,OACA,WAEA,yFACC,4BACA,6BACA,wBACA,SACA,mCACA,4BACA,2BAKA,wGACC,UACA,UACA,YAKH,uEACC,WACA,SACA,MACA,YAEA,YACA,gBAEA,kBAGD,iEACC,YACA,mCAIA,gBAKA,0BAEA,2EACC,aACA,YACA,iBACA,kBACA,iBACA,UAEA,0FACC,qBACA,kBACA,gBACA,uBACA,mBAED,kFACC,WACA,OACA,eAED,iFACC,WACA,OACA,eAID,sFACC,aAKF,8EACC,aAGD,8EACC,eACA,iBACA,aACA,mBACA,kBACA,QAEA,sFACC,QAxJK,KAyJL,WACA,YACA,aACA,mBACA,uBAGA,wGACC,aAQH,2GACC,yBAEA,6HACC,YACA,kBAIF,6GACC,yBAGD,6GACC,yBAIF,gEACC,iBACA,mCAEA,+EACC,WACA,cACA,YAMH,kHAEC,aAGD,sIAEC,kBACA,SACA,UACA,aACA,WAEA,kJACC,WACA,YACA,oBACA,QAzNO,KA0NP,kKACC,SACA,MA5NM,KA6NN,OA7NM,KAmOT,+DACC,OACA,YACA,aAGA,yFACC,gBACA,uBAMJ,+FACC,cAID,+CACC,aAEA,qEACC,qBACA,cAEA,aAEA,wEACC,iBAEA,iKAEC,aAGD,8EACI,cAQR,aACC,0DACA,YACA,SACA,aACA,WACA,YACA,mCACA,iCACA,YACA,gBAEA,uEAGC,UAGD,oEAEC,mEASF,cACC,eACA,MAOC,uGACC,gBAID,4EACC,WAKF,0BACC,kBACA,QACA,MAKF,gBACC,aAGD,8BACC,gBACA,sBACA,kBACA,kBACA,aACA,eACA,mBAEA,iCACC,WACA,eAGD,6DACC,aACA,YACA,cE/1CF,QACC,sBACA,YACA,WACA,qBACA,gBACA,gBACA,mBACA,kBACA,YAED,qBACC,kBACA,cACA,WACA,YACA,WACA,iBACA,eACA,WACA,YAED,iCACA,+FAEA,gDACC,sBAGD,uBACC,qBACA,mBACA,YACA,gBAED,0CACC,YACA,gBAED,mBACC,sCACA,sEACA,eACA,kBACA,WACA,YACA,YACA,qBACA,kBAEA,yCACC,gBAGF,yEACC,wBACA,SACA,UACA,kBACA,gBACA,8CAED,0BACC,QACA,UACA,gBACA,mBACA,mBAED,gCACC,wCACA,kBACA,cACA,YAED,gCACC,kBACA,6BAED,4BACC,cAED,2BACC,aAGD,yBACC,yBACA,4BAGD,uBACC,2BACA,yBACA,wBACA,sBACA,qBACA,iBACA,mBAGD,0HAGC,8BACA,4BACA,2BACA,yBACA,wBACA,oBAED,0CACC,cAED,6BACC,WAED,0BACC,eACA,gBAED,+CACC,iBAED,sCACC,YAED,gCACC,mBACA,6BAED,iCACC,gBAED,4CACC,aAED,iCACC,WACA,YAED,2CACC,WACA,qBACA,WAED,6BACC,WACA,YACA,uBACA,4BACA,0BACA,WAGD,qEAEC,WACA,UAED,kCACC,gBACA,iBAED,sDACC,WAED,sCACC,YAED,iCACC,sBACA,kBACA,SAED,sCACC,sBAGD,gCACC,WACA,iBAEA,wCACC,WAIF,mBACC,0CACA,uCACA,qCACA,kCAGD,sCACE,4BACA,qCAEF,mCACE,4BACA,qCAEF,iCACE,4BACA,qCAEF,8BACE,4BACA,qCC3MF,oGAEA,iCACC,iCAGD,2EAIC,aAID,SACC,UAID,wBACC,eAGD,mCACC,eAGD,2BACC,iBAID,sDACC,kBACA,cACA,SACA,UACA,WACA,gBAID,gCACC,aAKD,mDACC,WAGD,4BACC,wBAED,2BACC,yBAID,iBACC,cAID,0CAEC,0BACC,YAED,4CACC,aAID,4BACC,kBAID,uCACC,eCvFF,sCACC,gBACA,aAGD,0CACC,WAID,qCACC,qBACA,0BAGD,0CACC,iBACA,mBACA,WAEA,gGAEC,UAGF,sDACC,WACA,UAGD,uCACC,kBACA,mBACA,iBAGD,gDACC,SAGD,+BACC,WACA,cACA,4BACA,2BACA,qBACA,WACA,SACA,YAGD,0CACC,WACA,cACA,sBAGD,wCACC,4BAGD,wCACC,wBAGD,yBACC,kBACA,kBACA,iBACA,cACA,cAGD,wBACC,WACA,gBACA,qBACA,WACA,kBACA,wBACA,4BAGD,uBACC,mBACA,uBACA,gBAGD,uBACC,eACA,iBACA,mBAGD,0BACC,wBACA,qBACA,cACA,cAGD,2BACC,oCAGD,8BACC,mBACA,aACA,aAGD,mCACC,sBAGD,yBACC,WAGD,oBACC,kBACA,MACA,QACA,WACA,UACA,WACA,YCxHD,iBACE,uBACA,qBACA,YACA,YAGF,mBACE,sBAGF,0BACE,iBACA,uBAGF,6BACE,kBACA,QAGF,wBACE","file":"merged.css"}
\ No newline at end of file +{"version":3,"sourceRoot":"","sources":["files.scss","../../../core/css/functions.scss","upload.scss","mobile.scss","detailsView.scss","../../../core/css/whatsnew.scss"],"names":[],"mappings":"AAWA,SAEC,YACA,YACA,qBACA,WAED,oEACA,8BACA,kDAEC,+CAED,0BACC,oDAGD,mBACC,kBACA,aACA,SACA,4CACC,iBAIF,gBACC,aAGD,OACC,iBACA,YACA,aACA,aACA,mBAGD,6EAGC,yBACA,gCAID,kBACC,kBACA,WACA,gBACA,cACA,sBAEA,6CACC,aAGD,wBACC,wBACA,gBAEA,SAEA,WACA,cACA,0DAMD,wBACC,cACA,WAEA,mGAEC,8CAEA,6KACC,oCAKF,8DACC,oBAKH,yBACC,aAID,uCACC,cACA,WAGD,wBAGC,yBAEA,qBAGD,6FACC,+DAGD,iCACC,yDAGD,kFACC,0CAGD,4EACC,+DAID,gBCxEC,yCD2ED,iBC3EC,yCD8ED,oBC9EC,0CDiFD,qGCjFC,wCDuFD,0BCvFC,yCD0FD,2BC1FC,2CD6FD,mBC7FC,yCDgGD,2BChGC,4CDmGD,2BCnGC,0CDsGD,4BCtGC,4CD0GD,4CACC,WAGD,iCACC,WACA,YACA,eACA,SACA,eAGD,wCACC,aAGD,0CACC,WAGD,2BACC,YAED,4KAKC,+CAED,wMAKC,oDAGD,qCAEA,yDACC,oCAED,kCACC,iCACA,8BACA,4BACA,yBACA,mBAED,wGAIC,UACA,oCAGD,oBACC,oCAED,uBACC,6BAED,sBACC,cACA,aACA,YACA,sBACA,2BACA,sBACA,oCACC,kBAGF,kCACC,qBACA,mBAED,2BACC,eACA,iBAGD,uCACC,cAGD,yBACC,WACA,WACA,gBACA,qBACA,2BACA,WAED,wJAIC,kBAED,2CACC,eAED,4EAEC,mBAGD,kBAEC,4CACA,gBACA,mBAED,SACC,eACA,kBACA,+BACA,4BAED,qBACC,kBACA,aACA,UAGD,uBACC,kBACA,YAGD,0BACC,gBAED,uCACC,iBAED,8EAEC,2BACA,sBACA,kBAEA,gBAGD,qMAQC,gBACA,qPACC,MAIF,2BACC,0DACA,iBAGD,sDACC,iBAGD,+BACC,kBACA,aAED,kCACC,aAGD,0DAGC,WACA,kBAED,kDAEC,aACA,kBACA,2BACA,sBACA,YACA,iBACA,UAED,qCAEC,QACA,eACA,eACA,YAGA,8DACC,WAED,mEACC,WAGF,6BACC,qBACA,WACA,YACA,wBACA,2BACA,4BACA,gBACA,eACA,mCACA,eACA,kBACA,UAED,oCACC,eAID,2CACC,qCAGD,iDACC,qBACA,4BACA,YAED,uBACC,iBACA,kBACA,SAGD,6IACA,8FAEA,wCACC,kBACA,gBACA,uBACA,YAKA,kBACC,YACA,4BACC,QACA,YACA,aACA,gBACA,mBACA,uBACA,YACA,WACA,mBAID,+BACC,iBACA,aACA,uBACA,mBACA,kCACA,gBAEA,iDACC,iBACA,iBACA,wCACA,iCACA,oCACA,uBACA,mBACA,gBACA,uBACA,iBACA,kBAEA,uDACC,iBACA,sBAID,mEACC,gBAOL,iJAEC,wBAGD,mCACC,iCACA,8BACA,4BACA,yBAED,4BACC,WAGD,2CACC,uBACA,gBACA,kBACA,mBAKD,8BACC,kBACA,mBAEA,iBACA,OACA,SACA,YACA,cAEA,iBACA,eAEA,iBACA,oCACA,uBACA,mBAGD,mBACC,UAID,6DACC,WACA,eAID,iRAIC,UAID,0EACC,WAMA,wEACC,aAGD,oGACC,+CACA,wCACA,wBACA,yDACA,aAIF,oGAEC,mBAGD,+BACC,kBACA,WACA,eACA,gBACA,wJAGD,wFAEC,kBACA,UACA,YAGD,yCACC,qBACA,WAED,8CACC,kBACA,cACA,SACA,WACA,iBACA,kBACA,wDAEC,8CACA,8CACA,oBAEA,WACA,YACA,aACA,qBACA,uBAGF,8DACC,+CAGD,iDAGA,aACC,WAGD,iCACC,kBAID,mDAEC,gBAID,oCACC,qBACA,0BAGD,8EACC,0BAOA,kCACC,eAGD,sEACC,eAGD,sCACC,gBAIF,aACC,YACA,WACA,2BAGD,qCACC,wCAID,iBACI,kBACA,qBACA,sBAEJ,wBACI,aAEJ,mBACC,eACA,iBACA,iBAGD,0BACC,aAED,uBACC,kBACA,2BACA,mBAGD,8CACC,gBAIA,8BACC,eACA,iBACA,iBACA,WACA,2CACC,kBACA,0FAGC,kBACA,cACA,SACA,UACA,WACA,gBAED,mDACC,qBACA,sBAGF,0CACC,iBACA,oBACA,kBACA,mBAGA,oGACC,WAID,qIAEC,WAED,uDACC,WACA,0HACC,WAIH,wEACC,UAED,oCACC,+CACA,wCAGF,uGACC,WAED,wDACC,UAKF,4EACC,qBACA,eACA,gBACA,uBACA,sBACA,gBAGD,2CACC,yBAGD,yCACC,UAGD,kNAKC,UAGD,qCACC,gBAGD,0FAEC,WAGD,mDACC,eAGD,SACC,oCAGA,aAED,wCACC,WAEA,mBAKD,sBACC,aAED,2DAIC,+BAED,YACC,mBACA,mBACA,iBAED,wBACC,UAED,YACC,qBAGD,iBACC,WACA,aAED,6BACC,kBACA,mBACA,YAGA,gBAED,yBACC,kBAED,MACC,WACA,kBACA,MACA,OACA,QACA,SACA,8CACA,sCACA,wBACA,WACA,yBACA,8BACA,4BACA,6BACA,iCAED,kBACC,UAGD,aACC,gBACA,SACA,sBACA,eACA,gBACA,aAGA,oBACC,qBAKF,gBACC,sBACA,wBACA,gBACA,YACA,UACA,SACA,0DACA,WACA,yBACA,sBACA,qBACA,iBACA,aACA,MACA,kBAKE,0IACC,sBACA,qBACA,aACA,YACA,WACA,YACA,mBACA,uBAED,oFACC,aAQJ,0DACC,OAGD,6KAIC,qBACA,sBACA,0BAMA,sDACC,sBAED,yDACC,uDAIF,iJAGC,aAGD,oJAGC,WACA,YAGD,gCACC,kBAGD,YACC,mBAEA,uBACC,mCAIF,0DAEC,oCAED,qBACC,oCACA,4BACC,2BAIF,cACC,iBACA,kBACA,gBACA,6BACA,cACA,gBACA,YAEA,2BACC,aAGD,kCACC,UACA,kBACA,iBAIF,uBACC,oBACA,YACA,gBACA,+BACA,UACA,YACA,wBACA,sBAEA,6BACC,YAKA,oEACC,0BAIF,kCACC,WACA,mCAWA,kDACC,cACA,4CACA,0DACA,qDACC,WACA,YAMH,+CACC,aACA,+CACA,6BACA,aACA,cAGA,+DACC,cACA,kBACA,aACA,mCAEA,0fAKC,+BAEA,oxDAGC,+CAKH,kDACC,eACA,mBAGC,8EACC,YACA,eACA,kBACA,MAvDQ,MAwDR,OAxDQ,MAyDR,QAxDO,KAyDP,MACA,OACA,WAEA,yFACC,4BACA,6BACA,wBACA,SACA,mCACA,4BACA,2BAKA,wGACC,UACA,UACA,YAKH,uEACC,WACA,SACA,MACA,YAEA,YACA,gBAEA,kBAGD,iEACC,YACA,mCAIA,gBAKA,0BAEA,2EACC,aACA,YACA,iBACA,kBACA,iBACA,UAEA,0FACC,qBACA,kBACA,gBACA,uBACA,mBAED,kFACC,WACA,OACA,eAED,iFACC,WACA,OACA,eAID,sFACC,aAKF,8EACC,aAGD,8EACC,eACA,iBACA,aACA,mBACA,kBACA,QAEA,sFACC,QAxJK,KAyJL,WACA,YACA,aACA,mBACA,uBAGA,wGACC,aAQH,2GACC,yBAEA,6HACC,YACA,kBAIF,6GACC,yBAGD,6GACC,yBAIF,gEACC,iBACA,mCAEA,+EACC,WACA,cACA,YAMH,kHAEC,aAGD,sIAEC,kBACA,SACA,UACA,aACA,WAEA,kJACC,WACA,YACA,oBACA,QAzNO,KA0NP,kKACC,SACA,MA5NM,KA6NN,OA7NM,KAmOT,+DACC,OACA,YACA,aAGA,yFACC,gBACA,uBAMJ,+FACC,cAID,+CACC,aAEA,qEACC,qBACA,cAEA,aAEA,wEACC,iBAEA,iKAEC,aAGD,8EACI,cAQR,aACC,0DACA,YACA,SACA,aACA,WACA,YACA,mCACA,iCACA,YACA,gBAEA,uEAGC,UAGD,oEAEC,mEASF,cACC,eACA,MAOC,uGACC,gBAID,4EACC,WAKF,0BACC,kBACA,QACA,MAKF,gBACC,aAGD,8BACC,gBACA,sBACA,kBACA,kBACA,aACA,eACA,mBAEA,iCACC,WACA,eAGD,6DACC,aACA,YACA,cE/1CF,QACC,sBACA,YACA,WACA,qBACA,gBACA,gBACA,mBACA,kBACA,YAED,qBACC,kBACA,cACA,WACA,YACA,WACA,iBACA,eACA,WACA,YAED,iCACA,+FAEA,gDACC,sBAGD,uBACC,qBACA,mBACA,YACA,gBAED,0CACC,YACA,gBAED,mBACC,sCACA,sEACA,eACA,kBACA,WACA,YACA,YACA,qBACA,kBAEA,yCACC,gBAGF,yEACC,wBACA,SACA,UACA,kBACA,gBACA,8CAED,0BACC,QACA,UACA,gBACA,mBACA,mBAED,gCACC,wCACA,kBACA,cACA,YAED,gCACC,kBACA,6BAED,4BACC,cAED,2BACC,aAGD,yBACC,yBACA,4BAGD,uBACC,2BACA,yBACA,wBACA,sBACA,qBACA,iBACA,mBAGD,0HAGC,8BACA,4BACA,2BACA,yBACA,wBACA,oBAED,0CACC,cAED,6BACC,WAED,0BACC,eACA,gBAED,+CACC,iBAED,sCACC,YAED,gCACC,mBACA,6BAED,iCACC,gBAED,4CACC,aAED,iCACC,WACA,YAED,2CACC,WACA,qBACA,WAED,6BACC,WACA,YACA,uBACA,4BACA,0BACA,WAGD,qEAEC,WACA,UAED,kCACC,gBACA,iBAED,sDACC,WAED,sCACC,YAED,iCACC,sBACA,kBACA,SAED,sCACC,sBAGD,gCACC,WACA,iBAEA,wCACC,WAIF,mBACC,0CACA,uCACA,qCACA,kCAGD,sCACE,4BACA,qCAEF,mCACE,4BACA,qCAEF,iCACE,4BACA,qCAEF,8BACE,4BACA,qCC3MF,oGAEA,iCACC,iCAGD,2EAIC,aAID,SACC,UAID,wBACC,eAGD,mCACC,eAGD,2BACC,iBAID,sDACC,kBACA,cACA,SACA,UACA,WACA,gBAID,gCACC,aAKD,mDACC,WAGD,4BACC,wBAED,2BACC,yBAID,iBACC,cAID,0CAEC,0BACC,YAED,4CACC,aAID,4BACC,kBAID,uCACC,eCvFF,sCACC,gBACA,aAGD,0CACC,WAID,qCACC,qBACA,0BAGD,0CACC,iBACA,mBACA,WAEA,gGAEC,UAGF,sDACC,WACA,UAGD,uCACC,kBACA,mBACA,iBAGD,gDACC,SAGD,+BACC,WACA,cACA,4BACA,2BACA,qBACA,WACA,SACA,YAGD,0CACC,WACA,cACA,sBAGD,wCACC,4BAGD,wCACC,wBAGD,yBACC,kBACA,kBACA,iBACA,cACA,cAGD,wBACC,WACA,gBACA,qBACA,WACA,kBACA,wBACA,4BAGD,uBACC,mBACA,uBACA,gBAGD,uBACC,eACA,iBACA,mBAGD,0BACC,wBACA,qBACA,cACA,cAGD,2BACC,oCAGD,8BACC,mBACA,aACA,aAGD,mCACC,sBAGD,yBACC,WAGD,oBACC,kBACA,MACA,QACA,WACA,UACA,WACA,YCxHD,iBACE,uBACA,qBACA,YACA,YAGF,mBACE,sBAGF,0BACE,iBACA,uBAGF,6BACE,kBACA,QAGF,wBACE","file":"merged.css"}
\ No newline at end of file diff --git a/apps/files/js/tagsplugin.js b/apps/files/js/tagsplugin.js index 78bd7eec557..1b49c1df14a 100644 --- a/apps/files/js/tagsplugin.js +++ b/apps/files/js/tagsplugin.js @@ -111,6 +111,7 @@ var fileInfo = context.fileList.files[$file.index()]; var dir = context.dir || context.fileList.getCurrentDirectory(); var tags = $file.attr('data-tags'); + var isFile = $file.attr('data-type') === 'file'; if (_.isUndefined(tags)) { tags = ''; @@ -121,7 +122,7 @@ // Fake Node object for vue compatibility const node = { - type: 'folder', + type: isFile ? 'file' : 'folder', path: (dir + '/' + fileName).replace(/\/\/+/g, '/'), root: '/files/' + OC.getCurrentUser().uid } diff --git a/apps/files/src/actions/downloadAction.ts b/apps/files/src/actions/downloadAction.ts index 44e9fa4b379..13fcde61063 100644 --- a/apps/files/src/actions/downloadAction.ts +++ b/apps/files/src/actions/downloadAction.ts @@ -19,12 +19,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { emit } from '@nextcloud/event-bus' import { Permission, Node, FileType } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw' -import { registerFileAction, FileAction } from '../services/FileAction' +import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' import { generateUrl } from '@nextcloud/router' import type { Navigation } from '../services/Navigation' diff --git a/apps/files/src/actions/favoriteAction.spec.ts b/apps/files/src/actions/favoriteAction.spec.ts index 48a00094a0d..57957e67a33 100644 --- a/apps/files/src/actions/favoriteAction.spec.ts +++ b/apps/files/src/actions/favoriteAction.spec.ts @@ -22,7 +22,7 @@ import * as favoriteAction from './favoriteAction' import { action } from './favoriteAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Permission } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' @@ -120,6 +120,7 @@ describe('Favorite action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() diff --git a/apps/files/src/actions/favoriteAction.ts b/apps/files/src/actions/favoriteAction.ts index 1ae77b6fb21..a33aacf4947 100644 --- a/apps/files/src/actions/favoriteAction.ts +++ b/apps/files/src/actions/favoriteAction.ts @@ -20,13 +20,15 @@ * */ import { emit } from '@nextcloud/event-bus' +import { generateUrl } from '@nextcloud/router' +import { Permission, type Node } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' -import StarSvg from '@mdi/svg/svg/star.svg?raw' +import Vue from 'vue' + import StarOutlineSvg from '@mdi/svg/svg/star-outline.svg?raw' -import type { Node } from '@nextcloud/files' +import StarSvg from '@mdi/svg/svg/star.svg?raw' -import { generateUrl } from '@nextcloud/router' import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' import type { Navigation } from '../services/Navigation' @@ -54,7 +56,7 @@ export const favoriteNode = async (node: Node, view: Navigation, willFavorite: b } // Update the node webdav attribute - node.attributes.favorite = willFavorite ? 1 : 0 + Vue.set(node.attributes, 'favorite', willFavorite ? 1 : 0) // Dispatch event to whoever is interested if (willFavorite) { @@ -85,8 +87,9 @@ export const action = new FileAction({ }, enabled(nodes: Node[]) { - // We can only favorite nodes within files + // We can only favorite nodes within files and with permissions return !nodes.some(node => !node.root?.startsWith?.('/files')) + && nodes.every(node => node.permissions !== Permission.NONE) }, async exec(node: Node, view: Navigation) { diff --git a/apps/files/src/actions/sidebarAction.spec.ts b/apps/files/src/actions/sidebarAction.spec.ts index c4750092ebc..69eabe4be79 100644 --- a/apps/files/src/actions/sidebarAction.spec.ts +++ b/apps/files/src/actions/sidebarAction.spec.ts @@ -21,7 +21,7 @@ */ import { action } from './sidebarAction' import { expect } from '@jest/globals' -import { File } from '@nextcloud/files' +import { File, Permission } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import type { Navigation } from '../services/Navigation' import logger from '../logger' @@ -51,12 +51,29 @@ describe('Open sidebar action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() expect(action.enabled!([file], view)).toBe(true) }) + test('Disabled without permissions', () => { + window.OCA = { Files: { Sidebar: {} } } + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.NONE, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], view)).toBe(false) + + }) + test('Disabled if more than one node', () => { window.OCA = { Files: { Sidebar: {} } } diff --git a/apps/files/src/actions/sidebarAction.ts b/apps/files/src/actions/sidebarAction.ts index 141cd75ff19..6c553d97902 100644 --- a/apps/files/src/actions/sidebarAction.ts +++ b/apps/files/src/actions/sidebarAction.ts @@ -21,9 +21,9 @@ */ import { translate as t } from '@nextcloud/l10n' import InformationSvg from '@mdi/svg/svg/information-variant.svg?raw' -import type { Node } from '@nextcloud/files' +import { Permission, type Node } from '@nextcloud/files' -import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' +import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' export const ACTION_DETAILS = 'details' @@ -45,7 +45,7 @@ export const action = new FileAction({ return false } - return nodes[0].root?.startsWith('/files/') ?? false + return (nodes[0].root?.startsWith('/files/') && nodes[0].permissions !== Permission.NONE) ?? false }, async exec(node: Node) { diff --git a/apps/files/src/actions/viewInFolderAction.spec.ts b/apps/files/src/actions/viewInFolderAction.spec.ts index b16f2663f33..887ed5d47c6 100644 --- a/apps/files/src/actions/viewInFolderAction.spec.ts +++ b/apps/files/src/actions/viewInFolderAction.spec.ts @@ -48,12 +48,26 @@ describe('View in folder action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() expect(action.enabled!([file], view)).toBe(true) }) + test('Disabled without permissions', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.NONE, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], view)).toBe(false) + }) + test('Disabled for non-dav ressources', () => { const file = new File({ id: 1, @@ -107,13 +121,14 @@ describe('View in folder action execute tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.READ, }) const exec = await action.exec(file, view, '/') // Silent action expect(exec).toBe(null) expect(goToRouteMock).toBeCalledTimes(1) - expect(goToRouteMock).toBeCalledWith(null, { view: 'files' }, { dir: '/' }) + expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/' }) }) test('View in (sub) folder', async () => { @@ -126,13 +141,14 @@ describe('View in folder action execute tests', () => { root: '/files/admin', owner: 'admin', mime: 'text/plain', + permissions: Permission.READ, }) const exec = await action.exec(file, view, '/') // Silent action expect(exec).toBe(null) expect(goToRouteMock).toBeCalledTimes(1) - expect(goToRouteMock).toBeCalledWith(null, { view: 'files' }, { dir: '/Foo/Bar' }) + expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo/Bar' }) }) test('View in folder fails without node', async () => { diff --git a/apps/files/src/actions/viewInFolderAction.ts b/apps/files/src/actions/viewInFolderAction.ts index 67e276112dc..2f603e6cf3a 100644 --- a/apps/files/src/actions/viewInFolderAction.ts +++ b/apps/files/src/actions/viewInFolderAction.ts @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { Node, FileType } from '@nextcloud/files' +import { Node, FileType, Permission } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw' @@ -46,6 +46,10 @@ export const action = new FileAction({ return false } + if (node.permissions === Permission.NONE) { + return false + } + return node.type === FileType.File }, diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue index 58b914041b2..672d7a0de33 100644 --- a/apps/files/src/components/FileEntry.vue +++ b/apps/files/src/components/FileEntry.vue @@ -150,7 +150,7 @@ <script lang='ts'> import { debounce } from 'debounce' import { emit } from '@nextcloud/event-bus' -import { formatFileSize } from '@nextcloud/files' +import { formatFileSize, Permission } from '@nextcloud/files' import { Fragment } from 'vue-frag' import { showError, showSuccess } from '@nextcloud/dialogs' import { translate } from '@nextcloud/l10n' @@ -166,6 +166,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' import StarIcon from 'vue-material-design-icons/Star.vue' import Vue from 'vue' +import type moment from 'moment' import { ACTION_DETAILS } from '../actions/sidebarAction.ts' import { getFileActions, DefaultType } from '../services/FileAction.ts' @@ -173,7 +174,6 @@ import { hashCode } from '../utils/hashUtils.ts' import { isCachedPreview } from '../services/PreviewService.ts' import { useActionsMenuStore } from '../store/actionsmenu.ts' import { useFilesStore } from '../store/files.ts' -import type moment from 'moment' import { useKeyboardStore } from '../store/keyboard.ts' import { useSelectionStore } from '../store/selection.ts' import { useUserConfigStore } from '../store/userconfig.ts' @@ -336,11 +336,16 @@ export default Vue.extend({ } } + if (this.source?.permissions & Permission.READ) { + return { + download: this.source.basename, + href: this.source.source, + title: this.t('files', 'Download file {name}', { name: this.displayName }), + } + } + return { - download: this.source.basename, - href: this.source.source, - // TODO: Use first action title ? - title: this.t('files', 'Download file {name}', { name: this.displayName }), + is: 'span', } }, @@ -398,7 +403,15 @@ export default Vue.extend({ // Actions shown in the menu enabledMenuActions() { - return this.enabledActions.filter(action => action.default !== DefaultType.HIDDEN) + return [ + // Showing inline first for the NcActions inline prop + ...this.enabledInlineActions, + // Then the rest + ...this.enabledActions.filter(action => action.default !== DefaultType.HIDDEN), + ].filter((value, index, self) => { + // Then we filter duplicates to prevent inline actions to be shown twice + return index === self.findIndex(action => action.id === value.id) + }) }, openedMenu: { get() { @@ -602,7 +615,7 @@ export default Vue.extend({ }, openDetailsIfAvailable(event) { - const detailsAction = this.enabledDefaultActions.find(action => action.id === ACTION_DETAILS) + const detailsAction = this.enabledActions.find(action => action.id === ACTION_DETAILS) if (detailsAction) { event.preventDefault() event.stopPropagation() diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue index c1d5c041992..e215714882c 100644 --- a/apps/files/src/components/FilesListVirtual.vue +++ b/apps/files/src/components/FilesListVirtual.vue @@ -322,6 +322,7 @@ export default Vue.extend({ } .files-list__row-name-text { + color: var(--color-main-text); // Make some space for the outline padding: 5px 10px; margin-left: -10px; diff --git a/apps/files/src/store/files.ts b/apps/files/src/store/files.ts index ac62512988b..c36ebcfecc2 100644 --- a/apps/files/src/store/files.ts +++ b/apps/files/src/store/files.ts @@ -58,7 +58,7 @@ export const useFilesStore = function(...args) { // Update the store all at once const files = nodes.reduce((acc, node) => { if (!node.fileid) { - logger.warn('Trying to update/set a node without fileid', node) + logger.error('Trying to update/set a node without fileid', node) return acc } acc[node.fileid] = node diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index 73293668664..571db4faab3 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -129,9 +129,16 @@ export default () => { // Add a folder to the favorites paths array and update the views const addPathToFavorites = function(path: string) { const view = generateFolderView(path) + + // Skip if already exists + if (favoriteFolders.find(folder => folder === path)) { + return + } + // Update arrays favoriteFolders.push(path) favoriteFoldersViews.push(view) + // Update and sort views updateAndSortViews() Navigation.register(view) @@ -140,10 +147,18 @@ export default () => { // Remove a folder from the favorites paths array and update the views const removePathFromFavorites = function(path: string) { const id = generateIdFromPath(path) - const index = favoriteFolders.findIndex(f => f === path) + const index = favoriteFolders.findIndex(folder => folder === path) + + // Skip if not exists + if (index === -1) { + return + } + // Update arrays favoriteFolders.splice(index, 1) favoriteFoldersViews.splice(index, 1) + + // Update and sort views Navigation.remove(id) updateAndSortViews() } diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php index daafb92e322..05f35f32f0a 100644 --- a/apps/files/tests/Controller/ViewControllerTest.php +++ b/apps/files/tests/Controller/ViewControllerTest.php @@ -212,56 +212,6 @@ class ViewControllerTest extends TestCase { 'expanded' => false, 'unread' => 0, ], - 'shareoverview' => [ - 'id' => 'shareoverview', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 18, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shares'), - 'classes' => 'collapsible', - 'sublist' => [ - [ - 'id' => 'sharingout', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 16, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared with others'), - ], - [ - 'id' => 'sharingin', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 15, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared with you'), - ], - [ - 'id' => 'sharinglinks', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 17, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared by link', []), - ], - [ - 'id' => 'deletedshares', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 19, - 'name' => \OC::$server->getL10N('files_sharing')->t('Deleted shares'), - ], - [ - 'id' => 'pendingshares', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 19, - 'name' => \OC::$server->getL10N('files_sharing')->t('Pending shares'), - ], - ], - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'expanded' => false, - 'unread' => 0, - ] ]); $expected = new Http\TemplateResponse( @@ -292,30 +242,6 @@ class ViewControllerTest extends TestCase { 'id' => 'systemtagsfilter', 'content' => null, ], - 'sharingout' => [ - 'id' => 'sharingout', - 'content' => null, - ], - 'sharingin' => [ - 'id' => 'sharingin', - 'content' => null, - ], - 'sharinglinks' => [ - 'id' => 'sharinglinks', - 'content' => null, - ], - 'deletedshares' => [ - 'id' => 'deletedshares', - 'content' => null, - ], - 'pendingshares' => [ - 'id' => 'pendingshares', - 'content' => null - ], - 'shareoverview' => [ - 'id' => 'shareoverview', - 'content' => null, - ], ], 'hiddenFields' => [], 'showgridview' => null diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js deleted file mode 100644 index b9a60c73dab..00000000000 --- a/apps/files_sharing/js/app.js +++ /dev/null @@ -1,409 +0,0 @@ -/** - * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -if (!OCA.Sharing) { - /** - * @namespace OCA.Sharing - */ - OCA.Sharing = {} -} - -/** - * @namespace - */ -OCA.Sharing.App = { - - _inFileList: null, - _outFileList: null, - _overviewFileList: null, - _pendingFileList: null, - - initSharingIn($el) { - if (this._inFileList) { - return this._inFileList - } - - this._inFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.self', - sharedWithUser: true, - fileActions: this._createFileActions(), - config: OCA.Files.App.getFilesConfig(), - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._inFileList) - this._inFileList.appName = t('files_sharing', 'Shared with you') - this._inFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-shared"></div>' - + '<h2>' + t('files_sharing', 'Nothing shared with you yet') + '</h2>' - + '<p>' + t('files_sharing', 'Files and folders others share with you will show up here') + '</p>') - return this._inFileList - }, - - initSharingOut($el) { - if (this._outFileList) { - return this._outFileList - } - this._outFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.others', - sharedWithUser: false, - fileActions: this._createFileActions(), - config: OCA.Files.App.getFilesConfig(), - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._outFileList) - this._outFileList.appName = t('files_sharing', 'Shared with others') - this._outFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-shared"></div>' - + '<h2>' + t('files_sharing', 'Nothing shared yet') + '</h2>' - + '<p>' + t('files_sharing', 'Files and folders you share will show up here') + '</p>') - return this._outFileList - }, - - initSharingLinks($el) { - if (this._linkFileList) { - return this._linkFileList - } - this._linkFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.link', - linksOnly: true, - fileActions: this._createFileActions(), - config: OCA.Files.App.getFilesConfig(), - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._linkFileList) - this._linkFileList.appName = t('files_sharing', 'Shared by link') - this._linkFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-public"></div>' - + '<h2>' + t('files_sharing', 'No shared links') + '</h2>' - + '<p>' + t('files_sharing', 'Files and folders you share by link will show up here') + '</p>') - return this._linkFileList - }, - - initSharingDeleted($el) { - if (this._deletedFileList) { - return this._deletedFileList - } - this._deletedFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.deleted', - defaultFileActionsDisabled: true, - showDeleted: true, - sharedWithUser: true, - fileActions: this._restoreShareAction(), - config: OCA.Files.App.getFilesConfig(), - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._deletedFileList) - this._deletedFileList.appName = t('files_sharing', 'Deleted shares') - this._deletedFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-share"></div>' - + '<h2>' + t('files_sharing', 'No deleted shares') + '</h2>' - + '<p>' + t('files_sharing', 'Shares you deleted will show up here') + '</p>') - return this._deletedFileList - }, - - initSharingPening($el) { - if (this._pendingFileList) { - return this._pendingFileList - } - this._pendingFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.pending', - showPending: true, - detailsViewEnabled: false, - defaultFileActionsDisabled: true, - sharedWithUser: true, - fileActions: this._acceptShareAction(), - config: OCA.Files.App.getFilesConfig(), - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._pendingFileList) - this._pendingFileList.appName = t('files_sharing', 'Pending shares') - this._pendingFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-share"></div>' - + '<h2>' + t('files_sharing', 'No pending shares') + '</h2>' - + '<p>' + t('files_sharing', 'Shares you have received but not confirmed will show up here') + '</p>') - return this._pendingFileList - }, - - initShareingOverview($el) { - if (this._overviewFileList) { - return this._overviewFileList - } - this._overviewFileList = new OCA.Sharing.FileList( - $el, - { - id: 'shares.overview', - fileActions: this._createFileActions(), - config: OCA.Files.App.getFilesConfig(), - isOverview: true, - // The file list is created when a "show" event is handled, so - // it should be marked as "shown" like it would have been done - // if handling the event with the file list already created. - shown: true, - } - ) - - this._extendFileList(this._overviewFileList) - this._overviewFileList.appName = t('files_sharing', 'Shares') - this._overviewFileList.$el.find('.emptyfilelist.emptycontent').html('<div class="icon-share"></div>' - + '<h2>' + t('files_sharing', 'No shares') + '</h2>' - + '<p>' + t('files_sharing', 'Shares will show up here') + '</p>') - return this._overviewFileList - }, - - removeSharingIn() { - if (this._inFileList) { - this._inFileList.$fileList.empty() - } - }, - - removeSharingOut() { - if (this._outFileList) { - this._outFileList.$fileList.empty() - } - }, - - removeSharingLinks() { - if (this._linkFileList) { - this._linkFileList.$fileList.empty() - } - }, - - removeSharingDeleted() { - if (this._deletedFileList) { - this._deletedFileList.$fileList.empty() - } - }, - - removeSharingPending() { - if (this._pendingFileList) { - this._pendingFileList.$fileList.empty() - } - }, - - removeSharingOverview() { - if (this._overviewFileList) { - this._overviewFileList.$fileList.empty() - } - }, - - /** - * Destroy the app - */ - destroy() { - OCA.Files.fileActions.off('setDefault.app-sharing', this._onActionsUpdated) - OCA.Files.fileActions.off('registerAction.app-sharing', this._onActionsUpdated) - this.removeSharingIn() - this.removeSharingOut() - this.removeSharingLinks() - this._inFileList = null - this._outFileList = null - this._linkFileList = null - this._overviewFileList = null - delete this._globalActionsInitialized - }, - - _createFileActions() { - // inherit file actions from the files app - const fileActions = new OCA.Files.FileActions() - // note: not merging the legacy actions because legacy apps are not - // compatible with the sharing overview and need to be adapted first - fileActions.registerDefaultActions() - fileActions.merge(OCA.Files.fileActions) - - if (!this._globalActionsInitialized) { - // in case actions are registered later - this._onActionsUpdated = _.bind(this._onActionsUpdated, this) - OCA.Files.fileActions.on('setDefault.app-sharing', this._onActionsUpdated) - OCA.Files.fileActions.on('registerAction.app-sharing', this._onActionsUpdated) - this._globalActionsInitialized = true - } - - // when the user clicks on a folder, redirect to the corresponding - // folder in the files app instead of opening it directly - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename, context) { - OCA.Files.App.setActiveView('files', { silent: true }) - OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true) - }) - fileActions.setDefault('dir', 'Open') - return fileActions - }, - - _restoreShareAction() { - const fileActions = new OCA.Files.FileActions() - fileActions.registerAction({ - name: 'Restore', - displayName: t('files_sharing', 'Restore'), - altText: t('files_sharing', 'Restore share'), - mime: 'all', - permissions: OC.PERMISSION_ALL, - iconClass: 'icon-history', - type: OCA.Files.FileActions.TYPE_INLINE, - actionHandler(fileName, context) { - const shareId = context.$file.data('shareId') - $.post(OC.linkToOCS('apps/files_sharing/api/v1/deletedshares', 2) + shareId) - .success(function(result) { - context.fileList.remove(context.fileInfoModel.attributes.name) - }).fail(function() { - OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to restore the share.')) - }) - }, - }) - return fileActions - }, - - _acceptShareAction() { - const fileActions = new OCA.Files.FileActions() - fileActions.registerAction({ - name: 'Accept share', - displayName: t('files_sharing', 'Accept share'), - mime: 'all', - permissions: OC.PERMISSION_ALL, - iconClass: 'icon-checkmark', - type: OCA.Files.FileActions.TYPE_INLINE, - actionHandler(fileName, context) { - const shareId = context.$file.data('shareId') - let shareBase = 'shares/pending' - if (context.$file.attr('data-remote-id')) { - shareBase = 'remote_shares/pending' - } - $.post(OC.linkToOCS('apps/files_sharing/api/v1/' + shareBase, 2) + shareId) - .success(function(result) { - context.fileList.remove(context.fileInfoModel.attributes.name) - }).fail(function() { - OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to accept the share.')) - }) - }, - }) - fileActions.registerAction({ - name: 'Reject share', - displayName: t('files_sharing', 'Reject share'), - mime: 'all', - permissions: OC.PERMISSION_ALL, - iconClass: 'icon-close', - type: OCA.Files.FileActions.TYPE_INLINE, - shouldRender(context) { - // disable rejecting group shares from the pending list because they anyway - // land back into that same list - if (context.$file.attr('data-remote-id') && parseInt(context.$file.attr('data-share-type'), 10) === OC.Share.SHARE_TYPE_REMOTE_GROUP) { - return false - } - return true - }, - actionHandler(fileName, context) { - const shareId = context.$file.data('shareId') - let shareBase = 'shares' - if (context.$file.attr('data-remote-id')) { - shareBase = 'remote_shares' - } - - $.ajax({ - url: OC.linkToOCS('apps/files_sharing/api/v1/' + shareBase, 2) + shareId, - type: 'DELETE', - }).success(function(result) { - context.fileList.remove(context.fileInfoModel.attributes.name) - }).fail(function() { - OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to reject the share.')) - }) - }, - }) - return fileActions - }, - - _onActionsUpdated(ev) { - _.each([this._inFileList, this._outFileList, this._linkFileList], function(list) { - if (!list) { - return - } - - if (ev.action) { - list.fileActions.registerAction(ev.action) - } else if (ev.defaultAction) { - list.fileActions.setDefault( - ev.defaultAction.mime, - ev.defaultAction.name - ) - } - }) - }, - - _extendFileList(fileList) { - // remove size column from summary - fileList.fileSummary.$el.find('.filesize').remove() - }, -} - -window.addEventListener('DOMContentLoaded', function() { - $('#app-content-sharingin').on('show', function(e) { - OCA.Sharing.App.initSharingIn($(e.target)) - }) - $('#app-content-sharingin').on('hide', function() { - OCA.Sharing.App.removeSharingIn() - }) - $('#app-content-sharingout').on('show', function(e) { - OCA.Sharing.App.initSharingOut($(e.target)) - }) - $('#app-content-sharingout').on('hide', function() { - OCA.Sharing.App.removeSharingOut() - }) - $('#app-content-sharinglinks').on('show', function(e) { - OCA.Sharing.App.initSharingLinks($(e.target)) - }) - $('#app-content-sharinglinks').on('hide', function() { - OCA.Sharing.App.removeSharingLinks() - }) - $('#app-content-deletedshares').on('show', function(e) { - OCA.Sharing.App.initSharingDeleted($(e.target)) - }) - $('#app-content-deletedshares').on('hide', function() { - OCA.Sharing.App.removeSharingDeleted() - }) - $('#app-content-pendingshares').on('show', function(e) { - OCA.Sharing.App.initSharingPening($(e.target)) - }) - $('#app-content-pendingshares').on('hide', function() { - OCA.Sharing.App.removeSharingPending() - }) - $('#app-content-shareoverview').on('show', function(e) { - OCA.Sharing.App.initShareingOverview($(e.target)) - }) - $('#app-content-shareoverview').on('hide', function() { - OCA.Sharing.App.removeSharingOverview() - }) -}) diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js deleted file mode 100644 index 65eb1b78f5f..00000000000 --- a/apps/files_sharing/js/sharedfilelist.js +++ /dev/null @@ -1,541 +0,0 @@ -/* eslint-disable */ -/* - * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ -(function() { - - /** - * @class OCA.Sharing.FileList - * @augments OCA.Files.FileList - * - * @classdesc Sharing file list. - * Contains both "shared with others" and "shared with you" modes. - * - * @param $el container element with existing markup for the .files-controls - * and a table - * @param [options] map of options, see other parameters - * @param {boolean} [options.sharedWithUser] true to return files shared with - * the current user, false to return files that the user shared with others. - * Defaults to false. - * @param {boolean} [options.linksOnly] true to return only link shares - */ - var FileList = function($el, options) { - this.initialize($el, options) - } - FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, - /** @lends OCA.Sharing.FileList.prototype */ { - appName: 'Shares', - - /** - * Whether the list shows the files shared with the user (true) or - * the files that the user shared with others (false). - */ - _sharedWithUser: false, - _linksOnly: false, - _showDeleted: false, - _showPending: false, - _clientSideSort: true, - _allowSelection: false, - _isOverview: false, - - /** - * @private - */ - initialize: function($el, options) { - OCA.Files.FileList.prototype.initialize.apply(this, arguments) - if (this.initialized) { - return - } - - // TODO: consolidate both options - if (options && options.sharedWithUser) { - this._sharedWithUser = true - } - if (options && options.linksOnly) { - this._linksOnly = true - } - if (options && options.showDeleted) { - this._showDeleted = true - } - if (options && options.showPending) { - this._showPending = true - } - if (options && options.isOverview) { - this._isOverview = true - } - }, - - _renderRow: function() { - // HACK: needed to call the overridden _renderRow - // this is because at the time this class is created - // the overriding hasn't been done yet... - return OCA.Files.FileList.prototype._renderRow.apply(this, arguments) - }, - - _createRow: function(fileData) { - // TODO: hook earlier and render the whole row here - var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments) - $tr.find('.filesize').remove() - $tr.find('td.date').before($tr.children('td:first')) - $tr.find('td.filename input:checkbox').remove() - $tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(',')) - if (this._sharedWithUser) { - $tr.attr('data-share-owner', fileData.shareOwner) - $tr.attr('data-mounttype', 'shared-root') - var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE - $tr.attr('data-permissions', permission) - } - if (this._showDeleted || this._showPending) { - var permission = fileData.permissions - $tr.attr('data-share-permissions', permission) - } - - if (fileData.remoteId) { - $tr.attr('data-remote-id', fileData.remoteId) - } - - if (fileData.shareType) { - $tr.attr('data-share-type', fileData.shareType) - } - - // add row with expiration date for link only shares - influenced by _createRow of filelist - if (this._linksOnly) { - var expirationTimestamp = 0 - if (fileData.shares && fileData.shares[0].expiration !== null) { - expirationTimestamp = moment(fileData.shares[0].expiration).valueOf() - } - $tr.attr('data-expiration', expirationTimestamp) - - // date column (1000 milliseconds to seconds, 60 seconds, 60 minutes, 24 hours) - // difference in days multiplied by 5 - brightest shade for expiry dates in more than 32 days (160/5) - var modifiedColor = Math.round((expirationTimestamp - (new Date()).getTime()) / 1000 / 60 / 60 / 24 * 5) - // ensure that the brightest color is still readable - if (modifiedColor >= 160) { - modifiedColor = 160 - } - - var formatted - var text - if (expirationTimestamp > 0) { - formatted = OC.Util.formatDate(expirationTimestamp) - text = OC.Util.relativeModifiedDate(expirationTimestamp) - } else { - formatted = t('files_sharing', 'No expiration date set') - text = '' - modifiedColor = 160 - } - td = $('<td></td>').attr({ 'class': 'date' }) - td.append($('<span></span>').attr({ - 'class': 'modified', - 'title': formatted, - 'style': 'color:rgb(' + modifiedColor + ',' + modifiedColor + ',' + modifiedColor + ')' - }).text(text)) - - $tr.append(td) - } - return $tr - }, - - /** - * Set whether the list should contain outgoing shares - * or incoming shares. - * - * @param state true for incoming shares, false otherwise - */ - setSharedWithUser: function(state) { - this._sharedWithUser = !!state - }, - - updateEmptyContent: function() { - var dir = this.getCurrentDirectory() - if (dir === '/') { - // root has special permissions - this.$el.find('.emptyfilelist.emptycontent').toggleClass('hidden', !this.isEmpty) - this.$el.find('.files-filestable thead th').toggleClass('hidden', this.isEmpty) - - // hide expiration date header for non link only shares - if (!this._linksOnly) { - this.$el.find('th.column-expiration').addClass('hidden') - } - } else { - OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments) - } - }, - - getDirectoryPermissions: function() { - return OC.PERMISSION_READ | OC.PERMISSION_DELETE - }, - - updateStorageStatistics: function() { - // no op because it doesn't have - // storage info like free space / used space - }, - - reload: function() { - this.showMask() - if (this._reloadCall?.abort) { - this._reloadCall.abort() - } - - // there is only root - this._setCurrentDir('/', false) - - var promises = [] - - var deletedShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1', 2) + 'deletedshares', - /* jshint camelcase: false */ - data: { - format: 'json', - include_tags: true - }, - type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true') - } - } - - var pendingShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1/shares', 2) + 'pending', - /* jshint camelcase: false */ - data: { - format: 'json' - }, - type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true') - } - } - - var pendingRemoteShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1/remote_shares', 2) + 'pending', - /* jshint camelcase: false */ - data: { - format: 'json' - }, - type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true') - } - } - - var shares = { - url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares', - /* jshint camelcase: false */ - data: { - format: 'json', - shared_with_me: this._sharedWithUser !== false, - include_tags: true - }, - type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true') - } - } - - var remoteShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1') + 'remote_shares', - /* jshint camelcase: false */ - data: { - format: 'json', - include_tags: true - }, - type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true') - } - } - - // Add the proper ajax requests to the list and run them - // and make sure we have 2 promises - if (this._showDeleted) { - promises.push($.ajax(deletedShares)) - } else if (this._showPending) { - promises.push($.ajax(pendingShares)) - promises.push($.ajax(pendingRemoteShares)) - } else { - promises.push($.ajax(shares)) - - if (this._sharedWithUser !== false || this._isOverview) { - promises.push($.ajax(remoteShares)) - } - if (this._isOverview) { - shares.data.shared_with_me = !shares.data.shared_with_me - promises.push($.ajax(shares)) - } - } - - this._reloadCall = $.when.apply($, promises) - var callBack = this.reloadCallback.bind(this) - return this._reloadCall.then(callBack, callBack) - }, - - reloadCallback: function(shares, remoteShares, additionalShares) { - delete this._reloadCall - this.hideMask() - - this.$el.find('#headerSharedWith').text( - t('files_sharing', this._sharedWithUser ? 'Shared by' : 'Shared with') - ) - - var files = [] - - // make sure to use the same format - if (shares[0] && shares[0].ocs) { - shares = shares[0] - } - if (remoteShares && remoteShares[0] && remoteShares[0].ocs) { - remoteShares = remoteShares[0] - } - if (additionalShares && additionalShares[0] && additionalShares[0].ocs) { - additionalShares = additionalShares[0] - } - - if (shares.ocs && shares.ocs.data) { - files = files.concat(this._makeFilesFromShares(shares.ocs.data, this._sharedWithUser)) - } - - if (remoteShares && remoteShares.ocs && remoteShares.ocs.data) { - files = files.concat(this._makeFilesFromRemoteShares(remoteShares.ocs.data)) - } - - if (additionalShares && additionalShares.ocs && additionalShares.ocs.data) { - if (this._showPending) { - // in this case the second callback is about pending remote shares - files = files.concat(this._makeFilesFromRemoteShares(additionalShares.ocs.data)) - } else { - files = files.concat(this._makeFilesFromShares(additionalShares.ocs.data, !this._sharedWithUser)) - } - } - - this.setFiles(files) - return true - }, - - _makeFilesFromRemoteShares: function(data) { - var files = data - - files = _.chain(files) - // convert share data to file data - .map(function(share) { - var file = { - shareOwner: share.owner + '@' + share.remote.replace(/.*?:\/\//g, ''), - name: OC.basename(share.mountpoint), - mtime: share.mtime * 1000, - mimetype: share.mimetype, - type: share.type, - // remote share types are different and need to be mapped - shareType: (parseInt(share.share_type, 10) === 1) ? OC.Share.SHARE_TYPE_REMOTE_GROUP : OC.Share.SHARE_TYPE_REMOTE, - id: share.file_id, - path: OC.dirname(share.mountpoint), - permissions: share.permissions, - tags: share.tags || [] - } - - if (share.remote_id) { - // remote share - if (share.accepted !== '1') { - file.name = OC.basename(share.name) - file.path = '/' - } - file.remoteId = share.remote_id - file.shareOwnerId = share.owner - } - - if (!file.mimetype) { - // pending shares usually have no type, so default to showing a directory icon - file.mimetype = 'dir-shared' - } - - file.shares = [{ - id: share.id, - type: OC.Share.SHARE_TYPE_REMOTE - }] - return file - }) - .value() - return files - }, - - /** - * Converts the OCS API share response data to a file info - * list - * @param {Array} data OCS API share array - * @param {boolean} sharedWithUser - * @returns {Array.<OCA.Sharing.SharedFileInfo>} array of shared file info - */ - _makeFilesFromShares: function(data, sharedWithUser) { - /* jshint camelcase: false */ - var files = data - - if (this._linksOnly) { - files = _.filter(data, function(share) { - return share.share_type === OC.Share.SHARE_TYPE_LINK - }) - } - - // OCS API uses non-camelcased names - files = _.chain(files) - // convert share data to file data - .map(function(share) { - // TODO: use OC.Files.FileInfo - var file = { - id: share.file_source, - icon: OC.MimeType.getIconUrl(share.mimetype), - mimetype: share.mimetype, - hasPreview: share.has_preview, - tags: share.tags || [] - } - if (share.item_type === 'folder') { - file.type = 'dir' - file.mimetype = 'httpd/unix-directory' - } else { - file.type = 'file' - } - file.share = { - id: share.id, - type: share.share_type, - target: share.share_with, - stime: share.stime * 1000, - expiration: share.expiration - } - if (sharedWithUser) { - file.shareOwner = share.displayname_owner - file.shareOwnerId = share.uid_owner - file.name = OC.basename(share.file_target) - file.path = OC.dirname(share.file_target) - file.permissions = share.permissions - if (file.path) { - file.extraData = share.file_target - } - } else { - if (share.share_type !== OC.Share.SHARE_TYPE_LINK) { - file.share.targetDisplayName = share.share_with_displayname - file.share.targetShareWithId = share.share_with - } - file.name = OC.basename(share.path) - file.path = OC.dirname(share.path) - file.permissions = OC.PERMISSION_ALL - if (file.path) { - file.extraData = share.path - } - } - return file - }) - // Group all files and have a "shares" array with - // the share info for each file. - // - // This uses a hash memo to cumulate share information - // inside the same file object (by file id). - .reduce(function(memo, file) { - var data = memo[file.id] - var recipient = file.share.targetDisplayName - var recipientId = file.share.targetShareWithId - if (!data) { - data = memo[file.id] = file - data.shares = [file.share] - // using a hash to make them unique, - // this is only a list to be displayed - data.recipients = {} - data.recipientData = {} - // share types - data.shareTypes = {} - // counter is cheaper than calling _.keys().length - data.recipientsCount = 0 - data.mtime = file.share.stime - } else { - // always take the most recent stime - if (file.share.stime > data.mtime) { - data.mtime = file.share.stime - } - data.shares.push(file.share) - } - - if (recipient) { - // limit counterparts for output - if (data.recipientsCount < 4) { - // only store the first ones, they will be the only ones - // displayed - data.recipients[recipient] = true - data.recipientData[data.recipientsCount] = { - 'shareWith': recipientId, - 'shareWithDisplayName': recipient - } - } - data.recipientsCount++ - } - - data.shareTypes[file.share.type] = true - - delete file.share - return memo - }, {}) - // Retrieve only the values of the returned hash - .values() - // Clean up - .each(function(data) { - // convert the recipients map to a flat - // array of sorted names - data.mountType = 'shared' - delete data.recipientsCount - if (sharedWithUser) { - // only for outgoing shares - delete data.shareTypes - } else { - data.shareTypes = _.keys(data.shareTypes) - } - }) - // Finish the chain by getting the result - .value() - - // Sort by expected sort comparator - return files.sort(this._sortComparator) - } - }) - - /** - * Share info attributes. - * - * @typedef {Object} OCA.Sharing.ShareInfo - * - * @property {number} id share ID - * @property {number} type share type - * @property {String} target share target, either user name or group name - * @property {number} stime share timestamp in milliseconds - * @property {String} [targetDisplayName] display name of the recipient - * (only when shared with others) - * @property {String} [targetShareWithId] id of the recipient - * - */ - - /** - * Recipient attributes - * - * @typedef {Object} OCA.Sharing.RecipientInfo - * @property {String} shareWith the id of the recipient - * @property {String} shareWithDisplayName the display name of the recipient - */ - - /** - * Shared file info attributes. - * - * @typedef {OCA.Files.FileInfo} OCA.Sharing.SharedFileInfo - * - * @property {Array.<OCA.Sharing.ShareInfo>} shares array of shares for - * this file - * @property {number} mtime most recent share time (if multiple shares) - * @property {String} shareOwner name of the share owner - * @property {Array.<String>} recipients name of the first 4 recipients - * (this is mostly for display purposes) - * @property {Object.<OCA.Sharing.RecipientInfo>} recipientData (as object for easier - * passing to HTML data attributes with jQuery) - */ - - OCA.Sharing.FileList = FileList -})() diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index eff4a3ac5b7..946d82a3df7 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -117,7 +117,6 @@ class Application extends App implements IBootstrap { $context->injectFn([$this, 'registerMountProviders']); $context->injectFn([$this, 'registerEventsScripts']); $context->injectFn([$this, 'registerDownloadEvents']); - $context->injectFn([$this, 'setupSharingMenus']); Helper::registerHooks(); @@ -214,77 +213,4 @@ class Application extends App implements IBootstrap { } ); } - - public function setupSharingMenus(IManager $shareManager, IFactory $l10nFactory, IUserSession $userSession): void { - if (!$shareManager->shareApiEnabled() || !class_exists('\OCA\Files\App')) { - return; - } - - $navigationManager = \OCA\Files\App::getNavigationManager(); - // show_Quick_Access stored as string - $navigationManager->add(function () use ($shareManager, $l10nFactory, $userSession) { - $l = $l10nFactory->get('files_sharing'); - $user = $userSession->getUser(); - $userId = $user ? $user->getUID() : null; - - $sharingSublistArray = []; - - if ($shareManager->sharingDisabledForUser($userId) === false) { - $sharingSublistArray[] = [ - 'id' => 'sharingout', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 16, - 'name' => $l->t('Shared with others'), - ]; - } - - $sharingSublistArray[] = [ - 'id' => 'sharingin', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 15, - 'name' => $l->t('Shared with you'), - ]; - - if ($shareManager->sharingDisabledForUser($userId) === false) { - // Check if sharing by link is enabled - if ($shareManager->shareApiAllowLinks()) { - $sharingSublistArray[] = [ - 'id' => 'sharinglinks', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 17, - 'name' => $l->t('Shared by link'), - ]; - } - } - - $sharingSublistArray[] = [ - 'id' => 'deletedshares', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 19, - 'name' => $l->t('Deleted shares'), - ]; - - $sharingSublistArray[] = [ - 'id' => 'pendingshares', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 19, - 'name' => $l->t('Pending shares'), - ]; - - return [ - 'id' => 'shareoverview', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 18, - 'name' => $l->t('Shares'), - 'classes' => 'collapsible', - 'sublist' => $sharingSublistArray, - ]; - }); - } } diff --git a/apps/files_sharing/lib/Controller/DeletedShareAPIController.php b/apps/files_sharing/lib/Controller/DeletedShareAPIController.php index 19d1cbd0af6..33bd9eeb4cd 100644 --- a/apps/files_sharing/lib/Controller/DeletedShareAPIController.php +++ b/apps/files_sharing/lib/Controller/DeletedShareAPIController.php @@ -133,6 +133,8 @@ class DeletedShareAPIController extends OCSController { $result['file_source'] = $node->getId(); $result['file_parent'] = $node->getParent()->getId(); $result['file_target'] = $share->getTarget(); + $result['item_size'] = $node->getSize(); + $result['item_mtime'] = $node->getMTime(); $expiration = $share->getExpirationDate(); if ($expiration !== null) { diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index e2fb950dceb..5d5015cfca6 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -182,6 +182,11 @@ class ShareAPIController extends OCSController { $sharedBy = $this->userManager->get($share->getSharedBy()); $shareOwner = $this->userManager->get($share->getShareOwner()); + $isOwnShare = false; + if ($shareOwner !== null) { + $isOwnShare = $shareOwner->getUID() === $this->currentUser; + } + $result = [ 'id' => $share->getId(), 'share_type' => $share->getShareType(), @@ -225,6 +230,11 @@ class ShareAPIController extends OCSController { $result['item_type'] = 'file'; } + // Get the original node permission if the share owner is the current user + if ($isOwnShare) { + $result['item_permissions'] = $node->getPermissions(); + } + $result['mimetype'] = $node->getMimetype(); $result['has_preview'] = $this->previewManager->isAvailable($node); $result['storage_id'] = $node->getStorage()->getId(); @@ -233,6 +243,8 @@ class ShareAPIController extends OCSController { $result['file_source'] = $node->getId(); $result['file_parent'] = $node->getParent()->getId(); $result['file_target'] = $share->getTarget(); + $result['item_size'] = $node->getSize(); + $result['item_mtime'] = $node->getMTime(); $expiration = $share->getExpirationDate(); if ($expiration !== null) { @@ -1423,7 +1435,7 @@ class ShareAPIController extends OCSController { try { $formattedShare = $this->formatShare($share, $node); $formattedShare['status'] = $share->getStatus(); - $formattedShare['path'] = $share->getNode()->getName(); + $formattedShare['path'] = '/' . $share->getNode()->getName(); $formattedShare['permissions'] = 0; return $formattedShare; } catch (NotFoundException $e) { diff --git a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php index 8c11fec3999..583cd575793 100644 --- a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php +++ b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php @@ -29,6 +29,7 @@ use OCA\Files_Sharing\AppInfo\Application; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\Share\IManager; use OCP\Util; class LoadAdditionalListener implements IEventListener { @@ -37,10 +38,13 @@ class LoadAdditionalListener implements IEventListener { return; } - // After files for the files list shared content - Util::addScript(Application::APP_ID, 'files_sharing', 'files'); // After files for the breadcrumb share indicator Util::addScript(Application::APP_ID, 'additionalScripts', 'files'); Util::addStyle(Application::APP_ID, 'icons'); + + $shareManager = \OC::$server->get(IManager::class); + if ($shareManager->shareApiEnabled() && class_exists('\OCA\Files\App')) { + Util::addScript(Application::APP_ID, 'files_sharing', 'files'); + } } } diff --git a/apps/files_sharing/src/actions/acceptShareAction.spec.ts b/apps/files_sharing/src/actions/acceptShareAction.spec.ts new file mode 100644 index 00000000000..acef697b1aa --- /dev/null +++ b/apps/files_sharing/src/actions/acceptShareAction.spec.ts @@ -0,0 +1,223 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { action } from './acceptShareAction' +import { expect } from '@jest/globals' +import { File, Permission } from '@nextcloud/files' +import { FileAction } from '../../../files/src/services/FileAction' +import * as eventBus from '@nextcloud/event-bus' +import axios from '@nextcloud/axios' +import type { Navigation } from '../../../files/src/services/Navigation' +import '../main' + +const view = { + id: 'files', + name: 'Files', +} as Navigation + +const pendingShareView = { + id: 'pendingshares', + name: 'Pending shares', +} as Navigation + +describe('Accept share action conditions tests', () => { + test('Default values', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action).toBeInstanceOf(FileAction) + expect(action.id).toBe('accept-share') + expect(action.displayName([file], pendingShareView)).toBe('Accept share') + expect(action.iconSvgInline([file], pendingShareView)).toBe('<svg>SvgMock</svg>') + expect(action.default).toBeUndefined() + expect(action.order).toBe(1) + expect(action.inline).toBeDefined() + expect(action.inline!(file, pendingShareView)).toBe(true) + }) + + test('Default values for multiple files', () => { + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.displayName([file1, file2], pendingShareView)).toBe('Accept shares') + }) +}) + +describe('Accept share action enabled tests', () => { + test('Enabled with on pending shares view', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], pendingShareView)).toBe(true) + }) + + test('Disabled on wrong view', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], view)).toBe(false) + }) + + test('Disabled without nodes', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], pendingShareView)).toBe(false) + }) +}) + +describe('Accept share action execute tests', () => { + test('Accept share action', async () => { + jest.spyOn(axios, 'post') + jest.spyOn(eventBus, 'emit') + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(true) + expect(axios.post).toBeCalledTimes(1) + expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/pending/123') + + expect(eventBus.emit).toBeCalledTimes(1) + expect(eventBus.emit).toBeCalledWith('files:node:deleted', file) + }) + + test('Accept remote share action', async () => { + jest.spyOn(axios, 'post') + jest.spyOn(eventBus, 'emit') + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + remote: 3, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(true) + expect(axios.post).toBeCalledTimes(1) + expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/123') + + expect(eventBus.emit).toBeCalledTimes(1) + expect(eventBus.emit).toBeCalledWith('files:node:deleted', file) + }) + + test('Accept share action batch', async () => { + jest.spyOn(axios, 'post') + jest.spyOn(eventBus, 'emit') + + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foo.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/bar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 456, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.execBatch!([file1, file2], pendingShareView, '/') + + expect(exec).toStrictEqual([true, true]) + expect(axios.post).toBeCalledTimes(2) + expect(axios.post).toHaveBeenNthCalledWith(1, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/pending/123') + expect(axios.post).toHaveBeenNthCalledWith(2, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/pending/456') + + expect(eventBus.emit).toBeCalledTimes(2) + expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:node:deleted', file1) + expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:deleted', file2) + }) + + test('Accept fails', async () => { + jest.spyOn(axios, 'post').mockImplementation(() => { throw new Error('Mock error') }) + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(false) + expect(axios.post).toBeCalledTimes(1) + expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/pending/123') + + expect(eventBus.emit).toBeCalledTimes(0) + }) +}) diff --git a/apps/files_sharing/src/actions/acceptShareAction.ts b/apps/files_sharing/src/actions/acceptShareAction.ts new file mode 100644 index 00000000000..4be69633122 --- /dev/null +++ b/apps/files_sharing/src/actions/acceptShareAction.ts @@ -0,0 +1,66 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import type { Node } from '@nextcloud/files' +import type { Navigation } from '../../../files/src/services/Navigation' + +import { emit } from '@nextcloud/event-bus' +import { generateOcsUrl } from '@nextcloud/router' +import { translatePlural as n } from '@nextcloud/l10n' +import axios from '@nextcloud/axios' +import CheckSvg from '@mdi/svg/svg/check.svg?raw' + +import { FileAction, registerFileAction } from '../../../files/src/services/FileAction' +import { pendingSharesViewId } from '../views/shares' + +export const action = new FileAction({ + id: 'accept-share', + displayName: (nodes: Node[]) => n('files_sharing', 'Accept share', 'Accept shares', nodes.length), + iconSvgInline: () => CheckSvg, + + enabled: (nodes, view) => nodes.length > 0 && view.id === pendingSharesViewId, + + async exec(node: Node) { + try { + const isRemote = !!node.attributes.remote + const url = generateOcsUrl('apps/files_sharing/api/v1/{shareBase}/pending/{id}', { + shareBase: isRemote ? 'remote_shares' : 'shares', + id: node.attributes.id, + }) + await axios.post(url) + + // Remove from current view + emit('files:node:deleted', node) + + return true + } catch (error) { + return false + } + }, + async execBatch(nodes: Node[], view: Navigation, dir: string) { + return Promise.all(nodes.map(node => this.exec(node, view, dir))) + }, + + order: 1, + inline: () => true, +}) + +registerFileAction(action) diff --git a/apps/files_sharing/src/actions/openInFilesAction.spec.ts b/apps/files_sharing/src/actions/openInFilesAction.spec.ts new file mode 100644 index 00000000000..097f825bd36 --- /dev/null +++ b/apps/files_sharing/src/actions/openInFilesAction.spec.ts @@ -0,0 +1,97 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { action } from './openInFilesAction' +import { expect } from '@jest/globals' +import { File, Permission } from '@nextcloud/files' +import { DefaultType, FileAction } from '../../../files/src/services/FileAction' +import * as eventBus from '@nextcloud/event-bus' +import axios from '@nextcloud/axios' +import type { Navigation } from '../../../files/src/services/Navigation' +import '../main' +import { deletedSharesViewId, pendingSharesViewId, sharedWithOthersViewId, sharedWithYouViewId, sharesViewId, sharingByLinksViewId } from '../views/shares' + +const view = { + id: 'files', + name: 'Files', +} as Navigation + +const validViews = [ + sharesViewId, + sharedWithYouViewId, + sharedWithOthersViewId, + sharingByLinksViewId, +].map(id => ({ id, name: id })) as Navigation[] + +const invalidViews = [ + deletedSharesViewId, + pendingSharesViewId, +].map(id => ({ id, name: id })) as Navigation[] + +describe('Open in files action conditions tests', () => { + test('Default values', () => { + expect(action).toBeInstanceOf(FileAction) + expect(action.id).toBe('open-in-files') + expect(action.displayName([], validViews[0])).toBe('Open in files') + expect(action.iconSvgInline([], validViews[0])).toBe('') + expect(action.default).toBe(DefaultType.HIDDEN) + expect(action.order).toBe(-1000) + expect(action.inline).toBeUndefined() + }) +}) + +describe('Open in files action enabled tests', () => { + test('Enabled with on valid view', () => { + validViews.forEach(view => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], view)).toBe(true) + }) + }) + + test('Disabled on wrong view', () => { + invalidViews.forEach(view => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], view)).toBe(false) + }) + }) +}) + +describe('Open in files action execute tests', () => { + test('Open in files', async () => { + const goToRouteMock = jest.fn() + window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/Foo/foobar.txt', + owner: 'admin', + mime: 'text/plain', + root: '/files/admin', + permissions: Permission.READ, + }) + + const exec = await action.exec(file, view, '/') + // Silent action + expect(exec).toBe(null) + expect(goToRouteMock).toBeCalledTimes(1) + expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo' }) + }) +}) diff --git a/apps/files_sharing/src/actions/openInFilesAction.ts b/apps/files_sharing/src/actions/openInFilesAction.ts new file mode 100644 index 00000000000..4c60b2882b6 --- /dev/null +++ b/apps/files_sharing/src/actions/openInFilesAction.ts @@ -0,0 +1,56 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { translate as t } from '@nextcloud/l10n' +import type { Node } from '@nextcloud/files' + +import { registerFileAction, FileAction, DefaultType } from '../../../files/src/services/FileAction' +import { sharesViewId, sharedWithYouViewId, sharedWithOthersViewId, sharingByLinksViewId } from '../views/shares' + +export const action = new FileAction({ + id: 'open-in-files', + displayName: () => t('files', 'Open in files'), + iconSvgInline: () => '', + + enabled: (nodes, view) => [ + sharesViewId, + sharedWithYouViewId, + sharedWithOthersViewId, + sharingByLinksViewId, + // Deleted and pending shares are not + // accessible in the files app. + ].includes(view.id), + + async exec(node: Node) { + window.OCP.Files.Router.goToRoute( + null, // use default route + { view: 'files', fileid: node.fileid }, + { dir: node.dirname, fileid: node.fileid }, + ) + return null + }, + + default: DefaultType.HIDDEN, + // Before openFolderAction + order: -1000, +}) + +registerFileAction(action) diff --git a/apps/files_sharing/src/actions/rejectShareAction.spec.ts b/apps/files_sharing/src/actions/rejectShareAction.spec.ts new file mode 100644 index 00000000000..a075b45eedb --- /dev/null +++ b/apps/files_sharing/src/actions/rejectShareAction.spec.ts @@ -0,0 +1,250 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { action } from './rejectShareAction' +import { expect } from '@jest/globals' +import { File, Folder, Permission } from '@nextcloud/files' +import { FileAction } from '../../../files/src/services/FileAction' +import * as eventBus from '@nextcloud/event-bus' +import axios from '@nextcloud/axios' +import type { Navigation } from '../../../files/src/services/Navigation' +import '../main' + +const view = { + id: 'files', + name: 'Files', +} as Navigation + +const pendingShareView = { + id: 'pendingshares', + name: 'Pending shares', +} as Navigation + +describe('Reject share action conditions tests', () => { + test('Default values', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action).toBeInstanceOf(FileAction) + expect(action.id).toBe('reject-share') + expect(action.displayName([file], pendingShareView)).toBe('Reject share') + expect(action.iconSvgInline([file], pendingShareView)).toBe('<svg>SvgMock</svg>') + expect(action.default).toBeUndefined() + expect(action.order).toBe(2) + expect(action.inline).toBeDefined() + expect(action.inline!(file, pendingShareView)).toBe(true) + }) + + test('Default values for multiple files', () => { + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.displayName([file1, file2], pendingShareView)).toBe('Reject shares') + }) +}) + +describe('Reject share action enabled tests', () => { + test('Enabled with on pending shares view', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], pendingShareView)).toBe(true) + }) + + test('Disabled on wrong view', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], view)).toBe(false) + }) + + test('Disabled without nodes', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], pendingShareView)).toBe(false) + }) + + test('Disabled if some nodes are remote group shares', () => { + const folder1 = new Folder({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/Foo/', + owner: 'admin', + permissions: Permission.READ, + attributes: { + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + const folder2 = new Folder({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/Bar/', + owner: 'admin', + permissions: Permission.READ, + attributes: { + remote_id: 1, + share_type: window.OC.Share.SHARE_TYPE_REMOTE_GROUP, + }, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([folder1], pendingShareView)).toBe(true) + expect(action.enabled!([folder2], pendingShareView)).toBe(false) + expect(action.enabled!([folder1, folder2], pendingShareView)).toBe(false) + }) +}) + +describe('Reject share action execute tests', () => { + test('Reject share action', async () => { + jest.spyOn(axios, 'delete') + jest.spyOn(eventBus, 'emit') + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(true) + expect(axios.delete).toBeCalledTimes(1) + expect(axios.delete).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/123') + + expect(eventBus.emit).toBeCalledTimes(1) + expect(eventBus.emit).toBeCalledWith('files:node:deleted', file) + }) + + test('Reject remote share action', async () => { + jest.spyOn(axios, 'delete') + jest.spyOn(eventBus, 'emit') + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + remote: 3, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(true) + expect(axios.delete).toBeCalledTimes(1) + expect(axios.delete).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/remote_shares/123') + + expect(eventBus.emit).toBeCalledTimes(1) + expect(eventBus.emit).toBeCalledWith('files:node:deleted', file) + }) + + test('Reject share action batch', async () => { + jest.spyOn(axios, 'delete') + jest.spyOn(eventBus, 'emit') + + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foo.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/bar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 456, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.execBatch!([file1, file2], pendingShareView, '/') + + expect(exec).toStrictEqual([true, true]) + expect(axios.delete).toBeCalledTimes(2) + expect(axios.delete).toHaveBeenNthCalledWith(1, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/123') + expect(axios.delete).toHaveBeenNthCalledWith(2, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/456') + + expect(eventBus.emit).toBeCalledTimes(2) + expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:node:deleted', file1) + expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:deleted', file2) + }) + + test('Reject fails', async () => { + jest.spyOn(axios, 'delete').mockImplementation(() => { throw new Error('Mock error') }) + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, pendingShareView, '/') + + expect(exec).toBe(false) + expect(axios.delete).toBeCalledTimes(1) + expect(axios.delete).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/123') + + expect(eventBus.emit).toBeCalledTimes(0) + }) +}) diff --git a/apps/files_sharing/src/actions/rejectShareAction.ts b/apps/files_sharing/src/actions/rejectShareAction.ts new file mode 100644 index 00000000000..44dd36abe55 --- /dev/null +++ b/apps/files_sharing/src/actions/rejectShareAction.ts @@ -0,0 +1,83 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import type { Node } from '@nextcloud/files' +import type { Navigation } from '../../../files/src/services/Navigation' + +import { emit } from '@nextcloud/event-bus' +import { generateOcsUrl } from '@nextcloud/router' +import { translatePlural as n } from '@nextcloud/l10n' +import axios from '@nextcloud/axios' +import CloseSvg from '@mdi/svg/svg/close.svg?raw' + +import { FileAction, registerFileAction } from '../../../files/src/services/FileAction' +import { pendingSharesViewId } from '../views/shares' + +export const action = new FileAction({ + id: 'reject-share', + displayName: (nodes: Node[]) => n('files_sharing', 'Reject share', 'Reject shares', nodes.length), + iconSvgInline: () => CloseSvg, + + enabled: (nodes, view) => { + if (view.id !== pendingSharesViewId) { + return false + } + + if (nodes.length === 0) { + return false + } + + // disable rejecting group shares from the pending list because they anyway + // land back into that same list after rejecting them + if (nodes.some(node => node.attributes.remote_id + && node.attributes.share_type === window.OC.Share.SHARE_TYPE_REMOTE_GROUP)) { + return false + } + + return true + }, + + async exec(node: Node) { + try { + const isRemote = !!node.attributes.remote + const url = generateOcsUrl('apps/files_sharing/api/v1/{shareBase}/{id}', { + shareBase: isRemote ? 'remote_shares' : 'shares', + id: node.attributes.id, + }) + await axios.delete(url) + + // Remove from current view + emit('files:node:deleted', node) + + return true + } catch (error) { + return false + } + }, + async execBatch(nodes: Node[], view: Navigation, dir: string) { + return Promise.all(nodes.map(node => this.exec(node, view, dir))) + }, + + order: 2, + inline: () => true, +}) + +registerFileAction(action) diff --git a/apps/files_sharing/src/actions/restoreShareAction.spec.ts b/apps/files_sharing/src/actions/restoreShareAction.spec.ts new file mode 100644 index 00000000000..6b87d0549cf --- /dev/null +++ b/apps/files_sharing/src/actions/restoreShareAction.spec.ts @@ -0,0 +1,196 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { action } from './restoreShareAction' +import { expect } from '@jest/globals' +import { File, Permission } from '@nextcloud/files' +import { FileAction } from '../../../files/src/services/FileAction' +import * as eventBus from '@nextcloud/event-bus' +import axios from '@nextcloud/axios' +import type { Navigation } from '../../../files/src/services/Navigation' +import '../main' + +const view = { + id: 'files', + name: 'Files', +} as Navigation + +const deletedShareView = { + id: 'deletedshares', + name: 'Deleted shares', +} as Navigation + +describe('Restore share action conditions tests', () => { + test('Default values', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action).toBeInstanceOf(FileAction) + expect(action.id).toBe('restore-share') + expect(action.displayName([file], deletedShareView)).toBe('Restore share') + expect(action.iconSvgInline([file], deletedShareView)).toBe('<svg>SvgMock</svg>') + expect(action.default).toBeUndefined() + expect(action.order).toBe(1) + expect(action.inline).toBeDefined() + expect(action.inline!(file, deletedShareView)).toBe(true) + }) + + test('Default values for multiple files', () => { + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.displayName([file1, file2], deletedShareView)).toBe('Restore shares') + }) +}) + +describe('Restore share action enabled tests', () => { + test('Enabled with on pending shares view', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.ALL, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], deletedShareView)).toBe(true) + }) + + test('Disabled on wrong view', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], view)).toBe(false) + }) + + test('Disabled without nodes', () => { + expect(action.enabled).toBeDefined() + expect(action.enabled!([], deletedShareView)).toBe(false) + }) +}) + +describe('Restore share action execute tests', () => { + test('Restore share action', async () => { + jest.spyOn(axios, 'post') + jest.spyOn(eventBus, 'emit') + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, deletedShareView, '/') + + expect(exec).toBe(true) + expect(axios.post).toBeCalledTimes(1) + expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/deletedshares/123') + + expect(eventBus.emit).toBeCalledTimes(1) + expect(eventBus.emit).toBeCalledWith('files:node:deleted', file) + }) + + test('Restore share action batch', async () => { + jest.spyOn(axios, 'post') + jest.spyOn(eventBus, 'emit') + + const file1 = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foo.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const file2 = new File({ + id: 2, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/bar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 456, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.execBatch!([file1, file2], deletedShareView, '/') + + expect(exec).toStrictEqual([true, true]) + expect(axios.post).toBeCalledTimes(2) + expect(axios.post).toHaveBeenNthCalledWith(1, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/deletedshares/123') + expect(axios.post).toHaveBeenNthCalledWith(2, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/deletedshares/456') + + expect(eventBus.emit).toBeCalledTimes(2) + expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:node:deleted', file1) + expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:deleted', file2) + }) + + test('Restore fails', async () => { + jest.spyOn(axios, 'post').mockImplementation(() => { throw new Error('Mock error') }) + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.READ, + attributes: { + id: 123, + share_type: window.OC.Share.SHARE_TYPE_USER, + }, + }) + + const exec = await action.exec(file, deletedShareView, '/') + + expect(exec).toBe(false) + expect(axios.post).toBeCalledTimes(1) + expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/deletedshares/123') + + expect(eventBus.emit).toBeCalledTimes(0) + }) +}) diff --git a/apps/files_sharing/src/actions/restoreShareAction.ts b/apps/files_sharing/src/actions/restoreShareAction.ts new file mode 100644 index 00000000000..6c43b0cfb37 --- /dev/null +++ b/apps/files_sharing/src/actions/restoreShareAction.ts @@ -0,0 +1,65 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import type { Node } from '@nextcloud/files' +import type { Navigation } from '../../../files/src/services/Navigation' + +import { emit } from '@nextcloud/event-bus' +import { generateOcsUrl } from '@nextcloud/router' +import { translatePlural as n } from '@nextcloud/l10n' +import axios from '@nextcloud/axios' +import ArrowULeftTopSvg from '@mdi/svg/svg/arrow-u-left-top.svg?raw' + +import { FileAction, registerFileAction } from '../../../files/src/services/FileAction' +import { deletedSharesViewId } from '../views/shares' + +export const action = new FileAction({ + id: 'restore-share', + displayName: (nodes: Node[]) => n('files_sharing', 'Restore share', 'Restore shares', nodes.length), + + iconSvgInline: () => ArrowULeftTopSvg, + + enabled: (nodes, view) => nodes.length > 0 && view.id === deletedSharesViewId, + + async exec(node: Node) { + try { + const url = generateOcsUrl('apps/files_sharing/api/v1/deletedshares/{id}', { + id: node.attributes.id, + }) + await axios.post(url) + + // Remove from current view + emit('files:node:deleted', node) + + return true + } catch (error) { + return false + } + }, + async execBatch(nodes: Node[], view: Navigation, dir: string) { + return Promise.all(nodes.map(node => this.exec(node, view, dir))) + }, + + order: 1, + inline: () => true, +}) + +registerFileAction(action) diff --git a/apps/files_sharing/src/files_sharing.ts b/apps/files_sharing/src/files_sharing.ts new file mode 100644 index 00000000000..939cc91905d --- /dev/null +++ b/apps/files_sharing/src/files_sharing.ts @@ -0,0 +1,30 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * @author Julius Härtl <jus@bitgrid.net> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import registerSharingViews from './views/shares' + +import './actions/acceptShareAction' +import './actions/openInFilesAction' +import './actions/rejectShareAction' +import './actions/restoreShareAction' + +registerSharingViews() diff --git a/apps/files_sharing/src/index.js b/apps/files_sharing/src/main.ts index 95ed017bbf9..8462d5b542e 100644 --- a/apps/files_sharing/src/index.js +++ b/apps/files_sharing/src/main.ts @@ -22,7 +22,11 @@ */ // register default shares types -Object.assign(OC, { +if (!window.OC) { + window.OC = {} +} + +Object.assign(window.OC, { Share: { SHARE_TYPE_USER: 0, SHARE_TYPE_GROUP: 1, diff --git a/apps/files_sharing/src/services/SharingService.spec.ts b/apps/files_sharing/src/services/SharingService.spec.ts new file mode 100644 index 00000000000..a3269ac7180 --- /dev/null +++ b/apps/files_sharing/src/services/SharingService.spec.ts @@ -0,0 +1,364 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import { expect } from '@jest/globals' +import axios from '@nextcloud/axios' +import { Type } from '@nextcloud/sharing' +import * as auth from '@nextcloud/auth' + +import { getContents, type OCSResponse } from './SharingService' +import { File, Folder } from '@nextcloud/files' +import logger from './logger' + +global.window.OC = { + TAG_FAVORITE: '_$!<Favorite>!$_', +} + +describe('SharingService methods definitions', () => { + beforeAll(() => { + jest.spyOn(axios, 'get').mockImplementation(async (): Promise<any> => { + return { + data: { + ocs: { + meta: { + status: 'ok', + statuscode: 200, + message: 'OK', + }, + data: [], + }, + } as OCSResponse, + } + }) + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + + test('Shared with you', async () => { + await getContents(true, false, false, false, []) + + expect(axios.get).toHaveBeenCalledTimes(2) + expect(axios.get).toHaveBeenNthCalledWith(1, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + shared_with_me: true, + include_tags: true, + }, + }) + expect(axios.get).toHaveBeenNthCalledWith(2, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/remote_shares', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + include_tags: true, + }, + }) + }) + + test('Shared with others', async () => { + await getContents(false, true, false, false, []) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(axios.get).toHaveBeenCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + shared_with_me: false, + include_tags: true, + }, + }) + }) + + test('Pending shares', async () => { + await getContents(false, false, true, false, []) + + expect(axios.get).toHaveBeenCalledTimes(2) + expect(axios.get).toHaveBeenNthCalledWith(1, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares/pending', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + include_tags: true, + }, + }) + expect(axios.get).toHaveBeenNthCalledWith(2, 'http://localhost/ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + include_tags: true, + }, + }) + }) + + test('Deleted shares', async () => { + await getContents(false, true, false, false, []) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(axios.get).toHaveBeenCalledWith('http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares', { + headers: { + 'Content-Type': 'application/json', + }, + params: { + shared_with_me: false, + include_tags: true, + }, + }) + }) + + test('Unknown owner', async () => { + jest.spyOn(auth, 'getCurrentUser').mockReturnValue(null) + const results = await getContents(false, true, false, false, []) + + expect(results.folder.owner).toEqual(null) + }) +}) + +describe('SharingService filtering', () => { + beforeAll(() => { + jest.spyOn(axios, 'get').mockImplementation(async (): Promise<any> => { + return { + data: { + ocs: { + meta: { + status: 'ok', + statuscode: 200, + message: 'OK', + }, + data: [ + { + id: '62', + share_type: Type.SHARE_TYPE_USER, + uid_owner: 'test', + displayname_owner: 'test', + permissions: 31, + stime: 1688666292, + expiration: '2023-07-13 00:00:00', + token: null, + path: '/Collaborators', + item_type: 'folder', + item_permissions: 31, + mimetype: 'httpd/unix-directory', + storage: 224, + item_source: 419413, + file_source: 419413, + file_parent: 419336, + file_target: '/Collaborators', + item_size: 41434, + item_mtime: 1688662980, + }, + ], + }, + }, + } + }) + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + + test('Shared with others filtering', async () => { + const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_USER]) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(shares.contents).toHaveLength(1) + expect(shares.contents[0].fileid).toBe(419413) + expect(shares.contents[0]).toBeInstanceOf(Folder) + }) + + test('Shared with others filtering empty', async () => { + const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_LINK]) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(shares.contents).toHaveLength(0) + }) +}) + +describe('SharingService share to Node mapping', () => { + const shareFile = { + id: '66', + share_type: 0, + uid_owner: 'test', + displayname_owner: 'test', + permissions: 19, + can_edit: true, + can_delete: true, + stime: 1688721609, + parent: null, + expiration: '2023-07-14 00:00:00', + token: null, + uid_file_owner: 'test', + note: '', + label: null, + displayname_file_owner: 'test', + path: '/document.md', + item_type: 'file', + item_permissions: 27, + mimetype: 'text/markdown', + has_preview: true, + storage_id: 'home::test', + storage: 224, + item_source: 530936, + file_source: 530936, + file_parent: 419336, + file_target: '/document.md', + item_size: 123, + item_mtime: 1688721600, + share_with: 'user00', + share_with_displayname: 'User00', + share_with_displayname_unique: 'user00@domain.com', + status: { + status: 'away', + message: null, + icon: null, + clearAt: null, + }, + mail_send: 0, + hide_download: 0, + attributes: null, + tags: [], + } + + const shareFolder = { + id: '67', + share_type: 0, + uid_owner: 'test', + displayname_owner: 'test', + permissions: 31, + can_edit: true, + can_delete: true, + stime: 1688721629, + parent: null, + expiration: '2023-07-14 00:00:00', + token: null, + uid_file_owner: 'test', + note: '', + label: null, + displayname_file_owner: 'test', + path: '/Folder', + item_type: 'folder', + item_permissions: 31, + mimetype: 'httpd/unix-directory', + has_preview: false, + storage_id: 'home::test', + storage: 224, + item_source: 531080, + file_source: 531080, + file_parent: 419336, + file_target: '/Folder', + item_size: 0, + item_mtime: 1688721623, + share_with: 'user00', + share_with_displayname: 'User00', + share_with_displayname_unique: 'user00@domain.com', + status: { + status: 'away', + message: null, + icon: null, + clearAt: null, + }, + mail_send: 0, + hide_download: 0, + attributes: null, + tags: [window.OC.TAG_FAVORITE], + } + + test('File', async () => { + jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({ + data: { + ocs: { + data: [shareFile], + }, + }, + })) + + const shares = await getContents(false, true, false, false) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(shares.contents).toHaveLength(1) + + const file = shares.contents[0] as File + expect(file).toBeInstanceOf(File) + expect(file.fileid).toBe(530936) + expect(file.source).toBe('http://localhost/remote.php/dav/files/test/document.md') + expect(file.owner).toBe('test') + expect(file.mime).toBe('text/markdown') + expect(file.mtime).toBeInstanceOf(Date) + expect(file.size).toBe(123) + expect(file.permissions).toBe(27) + expect(file.root).toBe('/files/test') + expect(file.attributes).toBeInstanceOf(Object) + expect(file.attributes['has-preview']).toBe(true) + expect(file.attributes.previewUrl).toBe('/index.php/core/preview?fileId=530936&x=32&y=32&forceIcon=0') + expect(file.attributes.favorite).toBe(0) + }) + + test('Folder', async () => { + jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({ + data: { + ocs: { + data: [shareFolder], + }, + }, + })) + + const shares = await getContents(false, true, false, false) + + expect(axios.get).toHaveBeenCalledTimes(1) + expect(shares.contents).toHaveLength(1) + + const folder = shares.contents[0] as Folder + expect(folder).toBeInstanceOf(Folder) + expect(folder.fileid).toBe(531080) + expect(folder.source).toBe('http://localhost/remote.php/dav/files/test/Folder') + expect(folder.owner).toBe('test') + expect(folder.mime).toBe('httpd/unix-directory') + expect(folder.mtime).toBeInstanceOf(Date) + expect(folder.size).toBe(0) + expect(folder.permissions).toBe(31) + expect(folder.root).toBe('/files/test') + expect(folder.attributes).toBeInstanceOf(Object) + expect(folder.attributes['has-preview']).toBe(false) + expect(folder.attributes.previewUrl).toBeUndefined() + expect(folder.attributes.favorite).toBe(1) + }) + + test('Error', async () => { + jest.spyOn(logger, 'error').mockImplementationOnce(() => {}) + jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({ + data: { + ocs: { + data: [{}], + }, + }, + })) + + const shares = await getContents(false, true, false, false) + expect(shares.contents).toHaveLength(0) + expect(logger.error).toHaveBeenCalledTimes(1) + }) +}) diff --git a/apps/files_sharing/src/services/SharingService.ts b/apps/files_sharing/src/services/SharingService.ts new file mode 100644 index 00000000000..8d11c223b5d --- /dev/null +++ b/apps/files_sharing/src/services/SharingService.ts @@ -0,0 +1,181 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +/* eslint-disable camelcase, n/no-extraneous-import */ +import type { AxiosPromise } from 'axios' +import type { ContentsWithRoot } from '../../../files/src/services/Navigation' + +import { Folder, File } from '@nextcloud/files' +import { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router' +import { getCurrentUser } from '@nextcloud/auth' +import axios from '@nextcloud/axios' +import logger from './logger' + +export const rootPath = `/files/${getCurrentUser()?.uid}` + +export type OCSResponse = { + ocs: { + meta: { + status: string + statuscode: number + message: string + }, + data: [] + } +} + +const headers = { + 'Content-Type': 'application/json', +} + +const ocsEntryToNode = function(ocsEntry: any): Folder | File | null { + try { + const isFolder = ocsEntry?.item_type === 'folder' + const hasPreview = ocsEntry?.has_preview === true + const Node = isFolder ? Folder : File + + const fileid = ocsEntry.file_source + const previewUrl = hasPreview ? generateUrl('/core/preview?fileId={fileid}&x=32&y=32&forceIcon=0', { fileid }) : undefined + + // Generate path and strip double slashes + const path = ocsEntry?.path || ocsEntry.file_target + const source = generateRemoteUrl(`dav/${rootPath}/${path}`.replaceAll(/\/\//gm, '/')) + + // Prefer share time if more recent than item mtime + let mtime = ocsEntry?.item_mtime ? new Date((ocsEntry.item_mtime) * 1000) : undefined + if (ocsEntry?.stime > (ocsEntry?.item_mtime || 0)) { + mtime = new Date((ocsEntry.stime) * 1000) + } + + return new Node({ + id: fileid, + source, + owner: ocsEntry?.uid_owner, + mime: ocsEntry?.mimetype, + mtime, + size: ocsEntry?.item_size, + permissions: ocsEntry?.item_permissions || ocsEntry?.permissions, + root: rootPath, + attributes: { + ...ocsEntry, + previewUrl, + 'has-preview': hasPreview, + favorite: ocsEntry?.tags?.includes(window.OC.TAG_FAVORITE) ? 1 : 0, + }, + }) + } catch (error) { + logger.error('Error while parsing OCS entry', { error }) + return null + } +} + +const getShares = function(shared_with_me = false): AxiosPromise<OCSResponse> { + const url = generateOcsUrl('apps/files_sharing/api/v1/shares') + return axios.get(url, { + headers, + params: { + shared_with_me, + include_tags: true, + }, + }) +} + +const getSharedWithYou = function(): AxiosPromise<OCSResponse> { + return getShares(true) +} + +const getSharedWithOthers = function(): AxiosPromise<OCSResponse> { + return getShares() +} + +const getRemoteShares = function(): AxiosPromise<OCSResponse> { + const url = generateOcsUrl('apps/files_sharing/api/v1/remote_shares') + return axios.get(url, { + headers, + params: { + include_tags: true, + }, + }) +} + +const getPendingShares = function(): AxiosPromise<OCSResponse> { + const url = generateOcsUrl('apps/files_sharing/api/v1/shares/pending') + return axios.get(url, { + headers, + params: { + include_tags: true, + }, + }) +} + +const getRemotePendingShares = function(): AxiosPromise<OCSResponse> { + const url = generateOcsUrl('apps/files_sharing/api/v1/remote_shares/pending') + return axios.get(url, { + headers, + params: { + include_tags: true, + }, + }) +} + +const getDeletedShares = function(): AxiosPromise<OCSResponse> { + const url = generateOcsUrl('apps/files_sharing/api/v1/deletedshares') + return axios.get(url, { + headers, + params: { + include_tags: true, + }, + }) +} + +export const getContents = async (sharedWithYou = true, sharedWithOthers = true, pendingShares = false, deletedshares = false, filterTypes: number[] = []): Promise<ContentsWithRoot> => { + const promises = [] as AxiosPromise<OCSResponse>[] + + if (sharedWithYou) { + promises.push(getSharedWithYou(), getRemoteShares()) + } + if (sharedWithOthers) { + promises.push(getSharedWithOthers()) + } + if (pendingShares) { + promises.push(getPendingShares(), getRemotePendingShares()) + } + if (deletedshares) { + promises.push(getDeletedShares()) + } + + const responses = await Promise.all(promises) + const data = responses.map((response) => response.data.ocs.data).flat() + let contents = data.map(ocsEntryToNode).filter((node) => node !== null) as (Folder | File)[] + + if (filterTypes.length > 0) { + contents = contents.filter((node) => filterTypes.includes(node.attributes?.share_type)) + } + + return { + folder: new Folder({ + id: 0, + source: generateRemoteUrl('dav' + rootPath), + owner: getCurrentUser()?.uid || null, + }), + contents, + } +} diff --git a/apps/files_sharing/src/files_sharing.js b/apps/files_sharing/src/services/logger.ts index 0578da7f9c5..19be888bf1f 100644 --- a/apps/files_sharing/src/files_sharing.js +++ b/apps/files_sharing/src/services/logger.ts @@ -1,8 +1,7 @@ /** - * @copyright Copyright (c) 2016 John Molakvoæ <skjnldsv@protonmail.com> + * @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com> * * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Härtl <jus@bitgrid.net> * * @license AGPL-3.0-or-later * @@ -20,6 +19,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ +import { getLoggerBuilder } from '@nextcloud/logger' -import '../js/app.js' -import '../js/sharedfilelist.js' +export default getLoggerBuilder() + .setApp('files_sharing') + .detectUser() + .build() diff --git a/apps/files_sharing/src/views/shares.spec.ts b/apps/files_sharing/src/views/shares.spec.ts new file mode 100644 index 00000000000..353e82b6f84 --- /dev/null +++ b/apps/files_sharing/src/views/shares.spec.ts @@ -0,0 +1,125 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +/* eslint-disable n/no-extraneous-import */ +import { expect } from '@jest/globals' +import axios from '@nextcloud/axios' + +import { type Navigation } from '../../../files/src/services/Navigation' +import { type OCSResponse } from '../services/SharingService' +import NavigationService from '../../../files/src/services/Navigation' +import registerSharingViews from './shares' + +import '../main' +import { Folder } from '@nextcloud/files' + +describe('Sharing views definition', () => { + let Navigation + beforeEach(() => { + Navigation = new NavigationService() + window.OCP = { Files: { Navigation } } + }) + + afterAll(() => { + delete window.OCP + }) + + test('Default values', () => { + jest.spyOn(Navigation, 'register') + + expect(Navigation.views.length).toBe(0) + + registerSharingViews() + const shareOverviewView = Navigation.views.find(view => view.id === 'shareoverview') as Navigation + const sharesChildViews = Navigation.views.filter(view => view.parent === 'shareoverview') as Navigation[] + + expect(Navigation.register).toHaveBeenCalledTimes(6) + + // one main view and no children + expect(Navigation.views.length).toBe(6) + expect(shareOverviewView).toBeDefined() + expect(sharesChildViews.length).toBe(5) + + expect(shareOverviewView?.id).toBe('shareoverview') + expect(shareOverviewView?.name).toBe('Shares') + expect(shareOverviewView?.caption).toBe('Overview of shared files.') + expect(shareOverviewView?.icon).toBe('<svg>SvgMock</svg>') + expect(shareOverviewView?.order).toBe(20) + expect(shareOverviewView?.columns).toStrictEqual([]) + expect(shareOverviewView?.getContents).toBeDefined() + + const dataProvider = [ + { id: 'sharingin', name: 'Shared with you', caption: 'List of files that are shared with you.' }, + { id: 'sharingout', name: 'Shared with others', caption: 'List of files that you shared with others.' }, + { id: 'sharinglinks', name: 'Shared by link', caption: 'List of files that are shared by link.' }, + { id: 'deletedshares', name: 'Deleted shares', caption: 'List of shares that you removed yourself from.' }, + { id: 'pendingshares', name: 'Pending shares', caption: 'List of unapproved shares.' }, + ] + + sharesChildViews.forEach((view, index) => { + expect(view?.id).toBe(dataProvider[index].id) + expect(view?.parent).toBe('shareoverview') + expect(view?.name).toBe(dataProvider[index].name) + expect(view?.caption).toBe(dataProvider[index].caption) + expect(view?.icon).toBe('<svg>SvgMock</svg>') + expect(view?.order).toBe(index + 1) + expect(view?.columns).toStrictEqual([]) + expect(view?.getContents).toBeDefined() + }) + }) +}) + +describe('Sharing views contents', () => { + let Navigation + beforeEach(() => { + Navigation = new NavigationService() + window.OCP = { Files: { Navigation } } + }) + + afterAll(() => { + delete window.OCP + }) + + test('Sharing overview get contents', async () => { + jest.spyOn(axios, 'get').mockImplementation(async (): Promise<any> => { + return { + data: { + ocs: { + meta: { + status: 'ok', + statuscode: 200, + message: 'OK', + }, + data: [], + }, + } as OCSResponse, + } + }) + + registerSharingViews() + expect(Navigation.views.length).toBe(6) + Navigation.views.forEach(async (view: Navigation) => { + const content = await view.getContents('/') + expect(content.contents).toStrictEqual([]) + expect(content.folder).toBeInstanceOf(Folder) + }) + }) +}) diff --git a/apps/files_sharing/src/views/shares.ts b/apps/files_sharing/src/views/shares.ts new file mode 100644 index 00000000000..97d92adeb69 --- /dev/null +++ b/apps/files_sharing/src/views/shares.ts @@ -0,0 +1,126 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import type NavigationService from '../../../files/src/services/Navigation' +import type { Navigation } from '../../../files/src/services/Navigation' + +import { translate as t } from '@nextcloud/l10n' +import AccountClockSvg from '@mdi/svg/svg/account-clock.svg?raw' +import AccountGroupSvg from '@mdi/svg/svg/account-group.svg?raw' +import AccountSvg from '@mdi/svg/svg/account.svg?raw' +import DeleteSvg from '@mdi/svg/svg/delete.svg?raw' +import LinkSvg from '@mdi/svg/svg/link.svg?raw' +import ShareVariantSvg from '@mdi/svg/svg/share-variant.svg?raw' + +import { getContents } from '../services/SharingService' + +export const sharesViewId = 'shareoverview' +export const sharedWithYouViewId = 'sharingin' +export const sharedWithOthersViewId = 'sharingout' +export const sharingByLinksViewId = 'sharinglinks' +export const deletedSharesViewId = 'deletedshares' +export const pendingSharesViewId = 'pendingshares' + +export default () => { + const Navigation = window.OCP.Files.Navigation as NavigationService + Navigation.register({ + id: sharesViewId, + name: t('files_sharing', 'Shares'), + caption: t('files_sharing', 'Overview of shared files.'), + + icon: ShareVariantSvg, + order: 20, + + columns: [], + + getContents: () => getContents(), + } as Navigation) + + Navigation.register({ + id: sharedWithYouViewId, + name: t('files_sharing', 'Shared with you'), + caption: t('files_sharing', 'List of files that are shared with you.'), + + icon: AccountSvg, + order: 1, + parent: sharesViewId, + + columns: [], + + getContents: () => getContents(true, false, false, false), + } as Navigation) + + Navigation.register({ + id: sharedWithOthersViewId, + name: t('files_sharing', 'Shared with others'), + caption: t('files_sharing', 'List of files that you shared with others.'), + + icon: AccountGroupSvg, + order: 2, + parent: sharesViewId, + + columns: [], + + getContents: () => getContents(false, true, false, false), + } as Navigation) + + Navigation.register({ + id: sharingByLinksViewId, + name: t('files_sharing', 'Shared by link'), + caption: t('files_sharing', 'List of files that are shared by link.'), + + icon: LinkSvg, + order: 3, + parent: sharesViewId, + + columns: [], + + getContents: () => getContents(false, true, false, false, [window.OC.Share.SHARE_TYPE_LINK]), + } as Navigation) + + Navigation.register({ + id: deletedSharesViewId, + name: t('files_sharing', 'Deleted shares'), + caption: t('files_sharing', 'List of shares that you removed yourself from.'), + + icon: DeleteSvg, + order: 4, + parent: sharesViewId, + + columns: [], + + getContents: () => getContents(false, false, false, true), + } as Navigation) + + Navigation.register({ + id: pendingSharesViewId, + name: t('files_sharing', 'Pending shares'), + caption: t('files_sharing', 'List of unapproved shares.'), + + icon: AccountClockSvg, + order: 5, + parent: sharesViewId, + + columns: [], + + getContents: () => getContents(false, false, true, false), + } as Navigation) +} diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 2a2a7d940be..df63f61606f 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -576,6 +576,8 @@ class ShareAPIControllerTest extends TestCase { $file->method('getPath')->willReturn('file'); $file->method('getStorage')->willReturn($storage); $file->method('getParent')->willReturn($parentFolder); + $file->method('getSize')->willReturn(123465); + $file->method('getMTime')->willReturn(1234567890); $file->method('getMimeType')->willReturn('myMimeType'); $folder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); @@ -583,6 +585,8 @@ class ShareAPIControllerTest extends TestCase { $folder->method('getPath')->willReturn('folder'); $folder->method('getStorage')->willReturn($storage); $folder->method('getParent')->willReturn($parentFolder); + $folder->method('getSize')->willReturn(123465); + $folder->method('getMTime')->willReturn(1234567890); $folder->method('getMimeType')->willReturn('myFolderMimeType'); [$shareAttributes, $shareAttributesReturnJson] = $this->mockShareAttributes(); @@ -637,6 +641,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'status' => [], + 'item_size' => 123465, + 'item_mtime' => 1234567890, 'attributes' => null, ]; $data[] = [$share, $expected]; @@ -689,6 +695,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123465, + 'item_mtime' => 1234567890, 'attributes' => null, ]; $data[] = [$share, $expected]; @@ -747,6 +755,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123465, + 'item_mtime' => 1234567890, 'attributes' => null, ]; $data[] = [$share, $expected]; @@ -3735,6 +3745,13 @@ class ShareAPIControllerTest extends TestCase { $folder->method('getParent')->willReturn($parent); $fileWithPreview->method('getParent')->willReturn($parent); + $file->method('getSize')->willReturn(123456); + $folder->method('getSize')->willReturn(123456); + $fileWithPreview->method('getSize')->willReturn(123456); + $file->method('getMTime')->willReturn(1234567890); + $folder->method('getMTime')->willReturn(1234567890); + $fileWithPreview->method('getMTime')->willReturn(1234567890); + $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); $cache->method('getNumericStorageId')->willReturn(100); $storage = $this->createMock(Storage::class); @@ -3772,7 +3789,7 @@ class ShareAPIControllerTest extends TestCase { // User backend down $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_USER, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -3796,7 +3813,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipient', 'share_with_displayname_unique' => 'recipient', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'mail_send' => 0, 'mimetype' => 'myMimeType', 'has_preview' => false, @@ -3804,13 +3821,15 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'status' => [], + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => '[{"scope":"permissions","key":"download","enabled":true}]', ], $share, [], false ]; // User backend up $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_USER, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiatorDN', @@ -3823,7 +3842,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'ownerDN', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -3842,6 +3861,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'status' => [], + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => '[{"scope":"permissions","key":"download","enabled":true}]', ], $share, [ ['owner', $owner], @@ -3864,7 +3885,7 @@ class ShareAPIControllerTest extends TestCase { // User backend down $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_USER, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -3877,7 +3898,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -3896,6 +3917,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'status' => [], + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -3914,7 +3937,7 @@ class ShareAPIControllerTest extends TestCase { // User backend down $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_USER, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -3927,7 +3950,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'currentUser', 'displayname_file_owner' => 'currentUser', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -3946,6 +3969,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => true, 'can_delete' => true, 'status' => [], + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -3966,7 +3991,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_GROUP, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -3979,7 +4004,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -3996,6 +4021,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4014,7 +4041,7 @@ class ShareAPIControllerTest extends TestCase { ->setId(42); $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_GROUP, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4026,7 +4053,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -4043,6 +4070,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4064,7 +4093,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_LINK, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4097,6 +4126,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4119,7 +4150,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_LINK, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4151,6 +4182,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4170,7 +4203,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_REMOTE, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4182,7 +4215,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4199,6 +4232,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4218,7 +4253,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_REMOTE_GROUP, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4230,7 +4265,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4247,6 +4282,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4267,7 +4304,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_CIRCLE, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4280,7 +4317,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4298,6 +4335,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4316,7 +4355,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_CIRCLE, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4328,7 +4367,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4346,6 +4385,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4364,7 +4405,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_CIRCLE, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4376,7 +4417,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4394,6 +4435,8 @@ class ShareAPIControllerTest extends TestCase { 'hide_download' => 0, 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4427,7 +4470,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_EMAIL, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4439,7 +4482,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4459,6 +4502,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'password_expiration_time' => null, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4478,7 +4523,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_EMAIL, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4490,7 +4535,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', - 'label' => null, + 'label' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -4510,6 +4555,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => false, 'can_delete' => false, 'password_expiration_time' => null, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4529,7 +4576,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_USER, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4541,7 +4588,7 @@ class ShareAPIControllerTest extends TestCase { 'uid_file_owner' => 'currentUser', 'displayname_file_owner' => 'currentUser', 'note' => 'personal note', - 'label' => null, + 'label' => '', 'path' => 'fileWithPreview', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -4560,6 +4607,8 @@ class ShareAPIControllerTest extends TestCase { 'can_edit' => true, 'can_delete' => true, 'status' => [], + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, [], false ]; @@ -4659,6 +4708,9 @@ class ShareAPIControllerTest extends TestCase { $file->method('getParent')->willReturn($parent); + $file->method('getSize')->willReturn(123456); + $file->method('getMTime')->willReturn(1234567890); + $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); $cache->method('getNumericStorageId')->willReturn(100); $storage = $this->createMock(Storage::class); @@ -4683,7 +4735,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_ROOM, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4712,6 +4764,8 @@ class ShareAPIControllerTest extends TestCase { 'label' => '', 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, false, [] ]; @@ -4730,7 +4784,7 @@ class ShareAPIControllerTest extends TestCase { $result[] = [ [ - 'id' => 42, + 'id' => '42', 'share_type' => IShare::TYPE_ROOM, 'uid_owner' => 'initiator', 'displayname_owner' => 'initiator', @@ -4759,6 +4813,8 @@ class ShareAPIControllerTest extends TestCase { 'label' => '', 'can_edit' => false, 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, 'attributes' => null, ], $share, true, [ 'share_with_displayname' => 'recipientRoomName' diff --git a/apps/files_sharing/tests/js/appSpec.js b/apps/files_sharing/tests/js/appSpec.js deleted file mode 100644 index 4d2e5211d7c..00000000000 --- a/apps/files_sharing/tests/js/appSpec.js +++ /dev/null @@ -1,125 +0,0 @@ -/** -* @copyright 2014 Vincent Petry <pvince81@owncloud.com> - * - * @author Jan-Christoph Borchardt <hey@jancborchardt.net> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Vincent Petry <vincent@nextcloud.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -describe('OCA.Sharing.App tests', function() { - var App = OCA.Sharing.App; - var fileListIn; - var fileListOut; - - beforeEach(function() { - $('#testArea').append( - '<div id="app-navigation">' + - '<ul><li data-id="files"><a>Files</a></li>' + - '<li data-id="sharingin"><a></a></li>' + - '<li data-id="sharingout"><a></a></li>' + - '</ul></div>' + - '<div id="app-content">' + - '<div id="app-content-files" class="hidden">' + - '</div>' + - '<div id="app-content-sharingin" class="hidden">' + - '</div>' + - '<div id="app-content-sharingout" class="hidden">' + - '</div>' + - '</div>' + - '</div>' - ); - fileListIn = App.initSharingIn($('#app-content-sharingin')); - fileListOut = App.initSharingOut($('#app-content-sharingout')); - }); - afterEach(function() { - App.destroy(); - }); - - describe('initialization', function() { - it('inits sharing-in list on show', function() { - expect(fileListIn._sharedWithUser).toEqual(true); - }); - it('inits sharing-out list on show', function() { - expect(fileListOut._sharedWithUser).toBeFalsy(); - }); - }); - describe('file actions', function() { - it('provides default file actions', function() { - _.each([fileListIn, fileListOut], function(fileList) { - var fileActions = fileList.fileActions; - - expect(fileActions.actions.all).toBeDefined(); - expect(fileActions.actions.all.Delete).toBeDefined(); - expect(fileActions.actions.all.Rename).toBeDefined(); - expect(fileActions.actions.all.Download).toBeDefined(); - - expect(fileActions.defaults.dir).toEqual('Open'); - }); - }); - it('provides custom file actions', function() { - var actionStub = sinon.stub(); - // regular file action - OCA.Files.fileActions.register( - 'all', - 'RegularTest', - OC.PERMISSION_READ, - OC.imagePath('core', 'actions/shared'), - actionStub - ); - - App._inFileList = null; - fileListIn = App.initSharingIn($('#app-content-sharingin')); - - expect(fileListIn.fileActions.actions.all.RegularTest).toBeDefined(); - }); - it('redirects to files app when opening a directory', function() { - var oldList = OCA.Files.App.fileList; - // dummy new list to make sure it exists - OCA.Files.App.fileList = new OCA.Files.FileList($('<table><thead></thead><tbody></tbody></table>')); - - var setActiveViewStub = sinon.stub(OCA.Files.App, 'setActiveView'); - // create dummy table so we can click the dom - var $table = '<table><thead></thead><tbody class="files-fileList"></tbody></table>'; - $('#app-content-sharingin').append($table); - - App._inFileList = null; - fileListIn = App.initSharingIn($('#app-content-sharingin')); - - fileListIn.setFiles([{ - name: 'testdir', - type: 'dir', - path: '/somewhere/inside/subdir', - counterParts: ['user2'], - shareOwner: 'user2' - }]); - - fileListIn.findFileEl('testdir').find('td .nametext').click(); - - expect(OCA.Files.App.fileList.getCurrentDirectory()).toEqual('/somewhere/inside/subdir/testdir'); - - expect(setActiveViewStub.calledOnce).toEqual(true); - expect(setActiveViewStub.calledWith('files')).toEqual(true); - - setActiveViewStub.restore(); - - // restore old list - OCA.Files.App.fileList = oldList; - }); - }); -}); |