Skip to content

Commit

Permalink
Implement file extensions toggle (#6793)
Browse files Browse the repository at this point in the history
* Implement file extensions toggle

* Bump ods

* Remove useless file

* Change setting name

* Update snapshots

* Add mutation tests

* Fix snapshots after OcButton has target prop

Co-authored-by: Pascal Wengerter <[email protected]>
  • Loading branch information
Jan and pascalwengerter authored Apr 21, 2022
1 parent c800f6a commit 88c7fb5
Show file tree
Hide file tree
Showing 19 changed files with 128 additions and 31 deletions.
12 changes: 12 additions & 0 deletions changelog/unreleased/enhancement-add-show-file-extension-switch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Enhancement: Add show file extension toggle switch in file list settings

We've added a toggle switch to the file list settings to turn off and on displaying file extension.

If this setting is turned off, the file extension won't be shown anymore in:
* The name column displayed in the files list
* The right sidebar
* The rename modal
* The new file modal

https://github.com/owncloud/web/pull/6793
https://github.com/owncloud/web/issues/6730
12 changes: 10 additions & 2 deletions packages/web-app-files/src/components/AppBar/AppBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export default {
},
computed: {
...mapGetters('Files', ['files', 'selectedFiles']),
...mapState('Files', ['areHiddenFilesShown']),
...mapState('Files', ['areHiddenFilesShown', 'areFileExtensionsShown']),
pageTitle() {
const title = this.$route.meta.title
Expand Down Expand Up @@ -116,10 +116,18 @@ export default {
if (areHiddenFilesShownBoolean !== this.areHiddenFilesShown) {
this.SET_HIDDEN_FILES_VISIBILITY(areHiddenFilesShownBoolean)
}
// Storage returns a string so we need to convert it into a boolean
const areFileExtensionsShown = window.localStorage.getItem('oc_fileExtensionsShown') || 'true'
const areFileExtensionsShownBoolean = areFileExtensionsShown === 'true'
if (areFileExtensionsShownBoolean !== this.areFileExtensionsShown) {
this.SET_FILE_EXTENSIONS_VISIBILITY(areFileExtensionsShownBoolean)
}
},
methods: {
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY'])
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY', 'SET_FILE_EXTENSIONS_VISIBILITY'])
}
}
</script>
Expand Down
20 changes: 15 additions & 5 deletions packages/web-app-files/src/components/AppBar/CreateAndUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
</template>

<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
import pathUtil from 'path'
import Mixins from '../../mixins'
Expand Down Expand Up @@ -165,6 +165,7 @@ export default {
computed: {
...mapGetters(['getToken', 'capabilities', 'configuration', 'newFileHandlers', 'user']),
...mapGetters('Files', ['files', 'currentFolder', 'publicLinkPassword']),
...mapState('Files', ['areFileExtensionsShown']),
mimetypesAllowedForCreation() {
// we can't use `mapGetters` here because the External app doesn't exist in all deployments
Expand Down Expand Up @@ -334,10 +335,12 @@ export default {
) {
const defaultName = isFolder
? this.$gettext('New folder')
: this.$gettext('New file') + '.' + ext
: this.$gettext('New file') + (this.areFileExtensionsShown ? `.${ext}` : '')
const checkInputValue = (value) => {
this.setModalInputErrorMessage(
isFolder ? this.checkNewFolderName(value) : this.checkNewFileName(value)
isFolder
? this.checkNewFolderName(value)
: this.checkNewFileName(this.areFileExtensionsShown ? value : `${value}.${ext}`)
)
}
Expand All @@ -356,13 +359,20 @@ export default {
inputLabel: isFolder ? this.$gettext('Folder name') : this.$gettext('File name'),
inputError: isFolder
? this.checkNewFolderName(defaultName)
: this.checkNewFileName(defaultName),
: this.checkNewFileName(
this.areFileExtensionsShown ? defaultName : `${defaultName}.${ext}`
),
onCancel: this.hideModal,
onConfirm: isFolder
? this.addNewFolder
: addAppProviderFile
? this.addAppProviderFile
: this.addNewFile,
: (fileName) => {
if (!this.areFileExtensionsShown) {
fileName = `${fileName}.${ext}`
}
this.addNewFile(fileName)
},
onInput: checkInputValue
}
Expand Down
20 changes: 18 additions & 2 deletions packages/web-app-files/src/components/AppBar/ViewOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
:label="$gettext('Show hidden files')"
/>
</li>
<li class="files-view-options-list-item">
<oc-switch
v-model="fileExtensionsShownModel"
data-testid="files-switch-files-extensions-files"
:label="$gettext('Show file extensions')"
/>
</li>
<li class="files-view-options-list-item">
<oc-page-size
v-model="itemsPerPage"
Expand Down Expand Up @@ -57,7 +64,7 @@ export default {
}
},
computed: {
...mapState('Files', ['areHiddenFilesShown']),
...mapState('Files', ['areHiddenFilesShown', 'areFileExtensionsShown']),
viewOptionsButtonLabel() {
return this.$gettext('Display customization options of the files list')
Expand All @@ -71,10 +78,19 @@ export default {
set(value) {
this.SET_HIDDEN_FILES_VISIBILITY(value)
}
},
fileExtensionsShownModel: {
get() {
return this.areFileExtensionsShown
},
set(value) {
this.SET_FILE_EXTENSIONS_VISIBILITY(value)
}
}
},
methods: {
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY'])
...mapMutations('Files', ['SET_HIDDEN_FILES_VISIBILITY', 'SET_FILE_EXTENSIONS_VISIBILITY'])
}
}
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
:is-path-displayed="arePathsDisplayed"
:parent-folder-name-default="defaultParentFolderName"
:is-thumbnail-displayed="areThumbnailsDisplayed"
:is-extension-displayed="areFileExtensionsShown"
:is-resource-clickable="isResourceClickable(item.id)"
:folder-link="folderLink(item)"
:parent-folder-link="parentFolderLink(item)"
Expand Down Expand Up @@ -165,7 +166,7 @@
<script lang="ts">
import { DateTime } from 'luxon'
import maxSize from 'popper-max-size-modifier'
import { mapGetters, mapActions } from 'vuex'
import { mapGetters, mapActions, mapState } from 'vuex'
import { EVENT_TROW_MOUNTED, EVENT_FILE_DROPPED } from '../../constants'
import { SortDir } from '../../composables'
import * as path from 'path'
Expand Down Expand Up @@ -352,6 +353,7 @@ export default defineComponent({
},
computed: {
...mapGetters(['configuration']),
...mapState('Files', ['areFileExtensionsShown']),
popperOptions() {
return {
modifiers: [
Expand Down
4 changes: 3 additions & 1 deletion packages/web-app-files/src/components/SideBar/FileInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
:extension="file.extension"
:type="file.type"
:full-path="file.webDavPath"
:is-extension-displayed="areFileExtensionsShown"
:is-path-displayed="false"
/>
</h3>
Expand All @@ -30,7 +31,7 @@
import Mixins from '../../mixins'
import MixinResources from '../../mixins/resources'
import { isLocationSpacesActive, isLocationTrashActive } from '../../router'
import { mapGetters } from 'vuex'
import { mapGetters, mapState } from 'vuex'
import PrivateLinkItem from './PrivateLinkItem.vue'
import { useActiveLocation } from '../../composables'
Expand All @@ -54,6 +55,7 @@ export default {
},
computed: {
...mapGetters(['capabilities', 'user']),
...mapState('Files', ['areFileExtensionsShown']),
timeData() {
const interpolate = (obj) => {
obj.time = this.formDateFromRFC(obj.sourceTime)
Expand Down
33 changes: 28 additions & 5 deletions packages/web-app-files/src/mixins/actions/rename.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mapActions, mapGetters } from 'vuex'
import { mapActions, mapGetters, mapState } from 'vuex'
import { isSameResource, extractNameWithoutExtension } from '../../helpers/resource'
import { getParentPaths } from '../../helpers/path'
import { buildResource } from '../../helpers/resources'
Expand All @@ -8,6 +8,7 @@ export default {
computed: {
...mapGetters('Files', ['files', 'currentFolder']),
...mapGetters(['capabilities']),
...mapState('Files', ['areFileExtensionsShown']),

$_rename_items() {
return [
Expand Down Expand Up @@ -68,27 +69,49 @@ export default {
}

const confirmAction = (newName) => {
if (!this.areFileExtensionsShown) {
newName = `${newName}.${resources[0].extension}`
}

this.$_rename_renameResource(resources[0], newName)
}
const checkName = (newName) => {
if (!this.areFileExtensionsShown) {
newName = `${newName}.${resources[0].extension}`
}
this.$_rename_checkNewName(resources[0].name, newName, parentResources)
}
const nameWithoutExtension = extractNameWithoutExtension(resources[0])
const modalTitle =
!resources[0].isFolder && !this.areFileExtensionsShown
? nameWithoutExtension
: resources[0].name

const title = this.$gettextInterpolate(
resources[0].isFolder
? this.$gettext('Rename folder %{name}')
: this.$gettext('Rename file %{name}'),
{ name: resources[0].name }
{ name: modalTitle }
)
const nameWithoutExtension = extractNameWithoutExtension(resources[0])

const inputValue =
!resources[0].isFolder && !this.areFileExtensionsShown
? nameWithoutExtension
: resources[0].name

const inputSelectionRange =
resources[0].isFolder || !this.areFileExtensionsShown
? null
: [0, nameWithoutExtension.length]

const modal = {
variation: 'passive',
title,
cancelText: this.$gettext('Cancel'),
confirmText: this.$gettext('Rename'),
hasInput: true,
inputValue: resources[0].name,
inputSelectionRange: resources[0].isFolder ? null : [0, nameWithoutExtension.length],
inputValue,
inputSelectionRange,
inputLabel: resources[0].isFolder
? this.$gettext('Folder name')
: this.$gettext('File name'),
Expand Down
6 changes: 6 additions & 0 deletions packages/web-app-files/src/store/mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ export default {
state.areHiddenFilesShown = value

window.localStorage.setItem('oc_hiddenFilesShown', value)
},

SET_FILE_EXTENSIONS_VISIBILITY(state, value) {
state.areFileExtensionsShown = value

window.localStorage.setItem('oc_fileExtensionsShown', value)
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/web-app-files/src/store/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,6 @@ export default {
/**
* View settings
*/
areHiddenFilesShown: true
areHiddenFilesShown: true,
areFileExtensionsShown: true
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ function createStore(state = { selected: [] }) {
selectedFiles: () => state.selected
},
mutations: {
SET_HIDDEN_FILES_VISIBILITY: jest.fn()
SET_HIDDEN_FILES_VISIBILITY: jest.fn(),
SET_FILE_EXTENSIONS_VISIBILITY: jest.fn()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ describe('ViewOptions', () => {
Files: {
namespaced: true,
mutations: {
SET_HIDDEN_FILES_VISIBILITY: jest.fn()
SET_HIDDEN_FILES_VISIBILITY: jest.fn(),
SET_FILE_EXTENSIONS_VISIBILITY: jest.fn()
},
modules: {
sidebar: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ function getMountedWrapper(options = {}) {
store: createStore(Vuex.Store, {
getters: {
configuration: () => {}
},
modules: {
Files: {
namespaced: true
}
}
}),
propsData: {
Expand Down
9 changes: 9 additions & 0 deletions packages/web-app-files/tests/unit/store/mutations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ describe('vuex store mutations', () => {
expect(state.areHiddenFilesShown).toEqual(false)
})

it('SET_FILE_EXTENSIONS_VISIBILITY', () => {
const state = { areFileExtensionsShown: true }
const { SET_FILE_EXTENSIONS_VISIBILITY } = mutations

SET_FILE_EXTENSIONS_VISIBILITY(state, false)

expect(state.areFileExtensionsShown).toEqual(false)
})

describe('CURRENT_FILE_OUTGOING_SHARES_REMOVE', () => {
it('removes an outgoing user share', () => {
const shareToRemove = { id: 1, shareType: ShareTypes.user.value }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ exports[`SharedWithOthers view when the wrapper is not loading anymore when leng
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-left oc-table-cell-align-middle oc-table-cell-width-expand oc-text-truncate oc-table-data-cell oc-table-data-cell-name">
<div class="resource-table-resource-wrapper">
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isextensiondisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-button-stub type="button" size="medium" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" class="resource-table-edit-name"><span class="oc-icon oc-icon-s oc-icon-passive"><!----></span></oc-button-stub>
</div>
</td>
Expand All @@ -51,7 +51,7 @@ exports[`SharedWithOthers view when the wrapper is not loading anymore when leng
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-left oc-table-cell-align-middle oc-table-cell-width-expand oc-text-truncate oc-table-data-cell oc-table-data-cell-name">
<div class="resource-table-resource-wrapper">
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isextensiondisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-button-stub type="button" size="medium" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" class="resource-table-edit-name"><span class="oc-icon oc-icon-s oc-icon-passive"><!----></span></oc-button-stub>
</div>
</td>
Expand All @@ -74,7 +74,7 @@ exports[`SharedWithOthers view when the wrapper is not loading anymore when leng
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-left oc-table-cell-align-middle oc-table-cell-width-expand oc-text-truncate oc-table-data-cell oc-table-data-cell-name">
<div class="resource-table-resource-wrapper">
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isextensiondisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-button-stub type="button" size="medium" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" class="resource-table-edit-name"><span class="oc-icon oc-icon-s oc-icon-passive"><!----></span></oc-button-stub>
</div>
</td>
Expand All @@ -97,7 +97,7 @@ exports[`SharedWithOthers view when the wrapper is not loading anymore when leng
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-left oc-table-cell-align-middle oc-table-cell-width-expand oc-text-truncate oc-table-data-cell oc-table-data-cell-name">
<div class="resource-table-resource-wrapper">
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-resource-stub folderlink="[object Object]" parentfolderlink="[object Object]" resource="[object Object]" parentfoldernamedefault="All files and folders" ispathdisplayed="true" isextensiondisplayed="true" isresourceclickable="true"></oc-resource-stub>
<oc-button-stub type="button" size="medium" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" class="resource-table-edit-name"><span class="oc-icon oc-icon-s oc-icon-passive"><!----></span></oc-button-stub>
</div>
</td>
Expand Down
1 change: 1 addition & 0 deletions packages/web-app-files/tests/unit/views/views.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export const getStore = function ({
state.activeFiles.push(resource)
},
SET_HIDDEN_FILES_VISIBILITY: jest.fn(),
SET_FILE_EXTENSIONS_VISIBILITY: jest.fn(),
CLEAR_FILES_SEARCHED: () => {},
CLEAR_CURRENT_FILES_LIST: () => {},
LOAD_FILES: () => {},
Expand Down
2 changes: 1 addition & 1 deletion packages/web-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"luxon": "^2.3.0",
"marked": "^4.0.12",
"oidc-client": "1.11.5",
"owncloud-design-system": "^13.1.0-rc.3",
"owncloud-design-system": "^13.1.0-rc.5",
"owncloud-sdk": "~3.0.0-alpha.4",
"p-queue": "^6.1.1",
"popper-max-size-modifier": "^0.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`ApplicationsMenu component should render navigation with button and men
</oc-button-stub>
</li>
<li>
<oc-button-stub type="a" size="medium" href="http://some.org" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" target="_blank" class=""><span class="icon-box"><oc-icon-stub name="some-icon" filltype="fill" accessiblelabel="" type="span" size="medium" variation="passive" color=""></oc-icon-stub></span> <span>External</span>
<oc-button-stub type="a" size="medium" href="http://some.org" target="_blank" submit="button" variation="passive" appearance="raw" justifycontent="center" gapsize="medium" class=""><span class="icon-box"><oc-icon-stub name="some-icon" filltype="fill" accessiblelabel="" type="span" size="medium" variation="passive" color=""></oc-icon-stub></span> <span>External</span>
<!---->
</oc-button-stub>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`FeedbackLink component has no accessibility violations 1`] = `
<div class="oc-flex"><a aria-label="ownCloud feedback survey" href="https://owncloud.com/web-design-feedback" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-inverse oc-button-inverse-raw" target="_blank" aria-describedby="oc-feedback-link-description"><span class="oc-icon oc-icon-m oc-icon-passive"><!----></span></a>
<div class="oc-flex"><a aria-label="ownCloud feedback survey" href="https://owncloud.com/web-design-feedback" target="_blank" class="oc-button oc-rounded oc-button-m oc-button-justify-content-center oc-button-gap-m oc-button-inverse oc-button-inverse-raw" aria-describedby="oc-feedback-link-description"><span class="oc-icon oc-icon-m oc-icon-passive"><!----></span></a>
<p id="oc-feedback-link-description" class="oc-invisible-sr">Provide your feedback: We'd like to improve the web design and would be happy to hear your feedback. Thank you! Your ownCloud team.</p>
</div>
`;
Loading

0 comments on commit 88c7fb5

Please sign in to comment.