Skip to content

Commit

Permalink
Simplify link creation in Files/Sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalwengerter committed May 19, 2022
1 parent 7ae16cc commit f25cb13
Show file tree
Hide file tree
Showing 23 changed files with 504 additions and 720 deletions.
2 changes: 2 additions & 0 deletions changelog/unreleased/enhancement-redesign-link-sharing
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Enhancement: Redesign link sharing

We have redesigned the public link list in the right sidebar. Links now can be edited in-line and have a similiar look-and-feel to people and group shares.
Additionally, creating new links now is less cumbersome and the default name, while not configurable from the backend anymore, is now translated.

https://github.com/owncloud/web/pull/6749
https://github.com/owncloud/web/pull/6885
https://github.com/owncloud/web/pull/6961
276 changes: 150 additions & 126 deletions packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue
Original file line number Diff line number Diff line change
@@ -1,123 +1,95 @@
<template>
<div id="oc-files-file-link" class="oc-position-relative">
<div
v-show="currentView === VIEW_SHOW"
:key="VIEW_SHOW"
:aria-hidden="currentView !== VIEW_SHOW"
>
<oc-loader v-if="linksLoading" :aria-label="$gettext('Loading list of file links')" />
<template v-else>
<h3 class="oc-text-bold oc-m-rm oc-text-initial">
<span v-text="linksHeading" />
<oc-contextual-helper v-if="helpersEnabled" v-bind="viaLinkHelp" />
</h3>
<div v-if="canCreatePublicLinks" class="oc-mt-m">
<name-and-copy v-if="quicklink" :link="quicklink" />
<create-quick-link
v-else
:password-enforced="passwordEnforced"
:expiration-date="globalExpirationDate"
@createPublicLink="createLink"
/>
<oc-loader v-if="linksLoading" :aria-label="$gettext('Loading list of file links')" />
<template v-else>
<h3 class="oc-text-bold oc-m-rm oc-text-initial">
<span v-text="linksHeading" />
<oc-contextual-helper v-if="helpersEnabled" v-bind="viaLinkHelp" />
</h3>
<div v-if="canCreatePublicLinks" class="oc-mt-m">
<name-and-copy v-if="quicklink" :link="quicklink" />
<create-quick-link
v-else
:password-enforced="passwordEnforced"
:expiration-date="expirationDate"
@createPublicLink="checkLinkToCreate"
/>
<details-and-edit
v-if="quicklink"
:is-folder-share="highlightedFile.isFolder"
:link="quicklink"
:modifiable="canEdit"
:can-rename="false"
:password-enforced="passwordEnforced"
:expiration-date="expirationDate"
:available-role-options="availableRoleOptions"
@updateLink="checkLinkToCreate"
@removePublicLink="deleteLinkConfirmation"
/>
<hr class="link-separator oc-my-m" />
<oc-button
id="files-file-link-add"
variation="primary"
appearance="raw"
data-testid="files-link-add-btn"
@click="addNewLink"
v-text="addButtonLabel"
/>
</div>
<p
v-else
data-testid="files-links-no-reshare-permissions-message"
class="oc-mt-m"
v-text="noResharePermsMessage"
/>
<oc-list v-if="links.length" class="oc-overflow-hidden oc-my-m">
<li
v-for="link in displayLinks"
:key="link.key"
class="oc-py-s"
:data-testid="`files-link-id-${link.id}`"
>
<name-and-copy :link="link" />
<details-and-edit
v-if="quicklink"
:is-folder-share="highlightedFile.isFolder"
:link="quicklink"
:modifiable="canEdit"
:can-rename="false"
:link="link"
:modifiable="canEdit && !link.indirect"
:can-rename="true"
:password-enforced="passwordEnforced"
:expiration-date="globalExpirationDate"
:expiration-date="expirationDate"
:available-role-options="availableRoleOptions"
@updateLink="updatePublicLink"
@updateLink="checkLinkToUpdate"
@removePublicLink="deleteLinkConfirmation"
/>
<hr class="oc-my-m" />
<oc-button
id="files-file-link-add"
variation="primary"
appearance="raw"
data-testid="files-link-add-btn"
@click="addNewLink"
v-text="addButtonLabel"
/>
</div>
<p
v-else
data-testid="files-links-no-reshare-permissions-message"
class="oc-mt-m"
v-text="noResharePermsMessage"
/>
<oc-list v-if="links.length" class="oc-overflow-hidden oc-my-m">
<li
v-for="link in displayLinks"
:key="link.key"
class="oc-py-s"
:data-testid="`files-link-id-${link.id}`"
>
<name-and-copy :link="link" />
<details-and-edit
:is-folder-share="highlightedFile.isFolder"
:link="link"
:modifiable="canEdit && !link.indirect"
:can-rename="true"
:password-enforced="passwordEnforced"
:expiration-date="globalExpirationDate"
:available-role-options="availableRoleOptions"
@updateLink="updatePublicLink"
@removePublicLink="deleteLinkConfirmation"
/>
</li>
</oc-list>
<div v-if="links.length > 3" class="oc-flex oc-flex-center">
<oc-button
appearance="raw"
@click="toggleLinkListCollapsed"
v-text="collapseButtonTitle"
/>
</div>
</template>
</div>
<div
v-if="currentView === VIEW_CREATE"
:key="VIEW_CREATE"
:aria-hidden="currentView !== VIEW_CREATE"
>
<create-form
:default-link-name="defaultNewLinkName"
:password-enforced="passwordEnforced"
:expiration-date="globalExpirationDate"
:available-role-options="availableRoleOptions"
@createPublicLink="createLink"
@cancelLinkCreation="cancelCreation"
/>
</div>
</li>
</oc-list>
<div v-if="links.length > 3" class="oc-flex oc-flex-center">
<oc-button appearance="raw" @click="toggleLinkListCollapsed" v-text="collapseButtonTitle" />
</div>
</template>
</div>
</template>
<script lang="ts">
import { dirname } from 'path'
import { defineComponent } from '@vue/composition-api'
import { DateTime } from 'luxon'
import { mapGetters, mapActions, mapState } from 'vuex'
import { useStore, useCapabilitySpacesEnabled } from 'web-pkg/src/composables'
import { clientService } from 'web-pkg/src/services'
import mixins from '../../../mixins'
import { shareViaLinkHelp } from '../../../helpers/contextualHelpers'
import { getParentPaths } from '../../../helpers/path'
import { textUtils } from '../../../helpers/textUtils'
import { ShareTypes, LinkShareRoles, SharePermissions } from '../../../helpers/share'
import { cloneStateObject } from '../../../helpers/store'
import CreateForm from './Links/CreateForm.vue'
import { textUtils } from '../../../helpers/textUtils'
import { showQuickLinkPasswordModal } from '../../../quickActions'
import CreateQuickLink from './Links/CreateQuickLink.vue'
import DetailsAndEdit from './Links/DetailsAndEdit.vue'
import NameAndCopy from './Links/NameAndCopy.vue'
import CreateQuickLink from './Links/CreateQuickLink.vue'
import { ShareTypes, LinkShareRoles } from '../../../helpers/share'
import { useStore, useCapabilitySpacesEnabled } from 'web-pkg/src/composables'
import { clientService } from 'web-pkg/src/services'
import { dirname } from 'path'
import { defineComponent } from '@vue/composition-api'
import { shareViaLinkHelp } from '../../../helpers/contextualHelpers'
const VIEW_SHOW = 'showLinks'
const VIEW_CREATE = 'addPublicLink'
export default defineComponent({
name: 'FileLinks',
components: {
CreateForm,
CreateQuickLink,
DetailsAndEdit,
NameAndCopy
Expand All @@ -134,13 +106,6 @@ export default defineComponent({
return { graphClient, hasSpaces: useCapabilitySpacesEnabled(), linkListCollapsed }
},
data() {
return {
VIEW_SHOW,
VIEW_CREATE,
currentView: VIEW_SHOW
}
},
computed: {
...mapGetters('Files', [
'highlightedFile',
Expand All @@ -160,15 +125,11 @@ export default defineComponent({
return this.linkListCollapsed ? this.$gettext('Show more') : this.$gettext('Show less')
},
defaultNewLinkName() {
return this.capabilities?.files_sharing?.public?.defaultPublicLinkShareName || ''
},
quicklink() {
return this.currentFileOutgoingLinks.find((link) => link.quicklink === true)
},
globalExpirationDate() {
expirationDate() {
const expireDate = this.capabilities.files_sharing.public.expire_date
let defaultExpireDate = null
Expand Down Expand Up @@ -209,7 +170,6 @@ export default defineComponent({
label: this.$gettext(role.label)
}
})
// add empty permission link if oCIS for alias link
return [
// { role: null, name: 'Alias link', label: this.$gettext('Only invited people') },
Expand Down Expand Up @@ -274,10 +234,14 @@ export default defineComponent({
},
displayLinks() {
const linkShares = this.links
const sortedLinkShares = linkShares.sort((a, b) => {
return b.stime - a.stime
})
if (this.links.length > 3 && this.linkListCollapsed) {
return this.links.slice(0, 3)
return sortedLinkShares.slice(0, 3)
}
return this.links
return sortedLinkShares
},
indirectLinks() {
Expand Down Expand Up @@ -375,12 +339,66 @@ export default defineComponent({
return l1Direct ? -1 : 1
},
checkPasswordEnforcedFor(link) {
const currentRole = this.availableRoleOptions.find(({ role }) => {
return parseInt(link.permissions) === role.bitmask(false)
})
const canRead = currentRole.role.hasPermission(SharePermissions.read)
const canCreate = currentRole.role.hasPermission(SharePermissions.create)
const canDelete = currentRole.role.hasPermission(SharePermissions.delete)
if (this.passwordEnforced.read_only === true) {
return canRead && !canCreate && !canDelete
}
if (this.passwordEnforced.upload_only === true) {
return !canRead && canCreate && !canDelete
}
if (this.passwordEnforced.read_write === true) {
return canRead && canCreate && !canDelete
}
if (this.passwordEnforced.read_write_delete === true) {
return canRead && canCreate && canDelete
}
return false
},
addNewLink() {
this.currentView = VIEW_CREATE
this.checkLinkToCreate({
link: {
name: this.$gettext('Link'),
role: this.availableRoleOptions[0],
permissions: 1,
expiration: this.expirationDate.default,
password: false
}
})
},
cancelCreation() {
this.currentView = VIEW_SHOW
checkLinkToCreate({ link, onError = () => {} }) {
const paramsToCreate = this.getParamsForLink(link)
if (this.checkPasswordEnforcedFor(link)) {
showQuickLinkPasswordModal({ store: this.$store }, async (newPassword) => {
this.hideModal()
this.createLink({ params: { ...paramsToCreate, password: newPassword }, onError })
})
} else {
this.createLink({ params: paramsToCreate, onError })
}
},
checkLinkToUpdate({ link, onSuccess = () => {} }) {
const params = this.getParamsForLink(link)
if (this.checkPasswordEnforcedFor(link)) {
showQuickLinkPasswordModal({ store: this.$store }, async (newPassword) => {
this.hideModal()
this.updatePublicLink({ params: { ...params, password: newPassword }, onSuccess })
})
} else {
this.updatePublicLink({ params, onSuccess })
}
},
getParamsForLink(link) {
Expand Down Expand Up @@ -421,6 +439,7 @@ export default defineComponent({
return {
expireDate,
password,
id: link.id,
permissions: link.permissions,
quicklink: link.quicklink,
name: link.name,
Expand All @@ -430,29 +449,30 @@ export default defineComponent({
}
},
async createLink({ link, showError }) {
const params = this.getParamsForLink(link)
async createLink({ params, onError = (e) => {} }) {
await this.addLink({
path: this.highlightedFile.path,
client: this.$client,
$gettext: this.$gettext,
params,
storageId: this.currentStorageId
}).catch(showError)
this.currentView = VIEW_SHOW
}).catch((e) => {
onError(e)
console.error(e)
this.showMessage({
title: this.$gettext('Failed to create link'),
status: 'danger'
})
})
this.showMessage({
title: this.$gettext('Link was created successfully')
})
},
async updatePublicLink({ link, onSuccess = () => {}, onError = (e) => {} }) {
const params = this.getParamsForLink(link)
async updatePublicLink({ params, onSuccess = () => {}, onError = (e) => {} }) {
await this.updateLink({
id: link.id,
id: params.id,
client: this.$client,
params
})
Expand Down Expand Up @@ -517,4 +537,8 @@ export default defineComponent({
background-color: var(--oc-color-input-bg);
border: 1px solid var(--oc-color-input-border);
}
.link-separator {
background: var(--oc-color-input-border);
height: 2px;
}
</style>
Loading

0 comments on commit f25cb13

Please sign in to comment.