Skip to content

Commit

Permalink
fixup! Add OCA.Files.Sidebar
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <[email protected]>
  • Loading branch information
skjnldsv committed Sep 16, 2019
1 parent 48da695 commit 00ff19d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 49 deletions.
7 changes: 6 additions & 1 deletion apps/files_sharing/src/components/SharingEntryInternal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<div class="avatar-external icon-external-white"></div>
</template>

<ActionLink :href="internalLink" target="_blank"
<ActionLink ref="copyButton" :href="internalLink" target="_blank"
:icon="copied && copySuccess ? 'icon-checkmark-color' : 'icon-clippy'"
@click.prevent="copyLink">{{ clipboardTooltip }}</ActionLink>
</SharingEntrySimple>
Expand Down Expand Up @@ -76,6 +76,11 @@ export default {
async copyLink() {
try {
await this.$copyText(this.internalLink)
this.$el.focus()
this.$nextTick(() => {
// focus and show the tooltip
this.$refs.copyButton.$el.focus()
})
this.copySuccess = true
this.copied = true
} catch (error) {
Expand Down
118 changes: 81 additions & 37 deletions apps/files_sharing/src/components/SharingEntryLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

<!-- clipboard -->
<Actions ref="copyButton" v-if="share && !isEmailShareType && share.token"
:disable-tooltip="true" class="sharing-entry__copy">
class="sharing-entry__copy">
<ActionLink :href="shareLink" target="_blank"
:icon="copied && copySuccess ? 'icon-checkmark-color' : 'icon-clippy'"
@click.stop.prevent="copyLink">{{ clipboardTooltip }}</ActionLink>
Expand Down Expand Up @@ -64,7 +64,14 @@
<ActionInput v-if="pendingPassword || share.password"
:value.sync="share.password"
:disabled="saving"
:required="config.enableLinkPasswordByDefault || config.enforcePasswordForPublicLink"
:minlength="config.passwordPolicy && config.passwordPolicy.minLength"
icon=""
v-tooltip.auto="{
content: errors.password,
show: errors.password,
trigger: 'manual'
}"
autocomplete="new-password"
@submit="onNewLinkShare">
{{ t('files_sharing', 'Enter a password') }}
Expand All @@ -81,9 +88,15 @@
:value="share.expireDate"
icon=""
type="date"
v-tooltip.auto="{
content: errors.expireDate,
show: errors.expireDate,
trigger: 'manual'
}"
:not-before="dateTomorrow"
:not-after="dateMaxEnforced"
@update:value="onNewLinkShare">
:not-after="dateMaxEnforced">
<!-- let's not submit when picked, the user
might want to still edit or copy the password -->
{{ t('files_sharing', 'Enter a date') }}
</ActionInput>

Expand All @@ -95,24 +108,33 @@
<!-- actions -->
<Actions v-else-if="!loading" class="sharing-entry__actions"
menu-align="right" :open.sync="open"
@close="onMenuClose">
@close="onPasswordSubmit">
<template v-if="share">
<template v-if="isShareOwner">
<!-- folder -->
<template v-if="isFolder && fileHasCreatePermission && this.config.isPublicUploadEnabled">
<ActionCheckbox :checked="share.permissions === publicUploadRValue"
<ActionRadio :checked="share.permissions === publicUploadRValue"
:value="publicUploadRValue"
:name="randomId"
:disabled="saving"
@change="togglePermissions">{{ t('files_sharing', 'Read only') }}</ActionCheckbox>
<ActionCheckbox :checked="share.permissions === publicUploadRWValue"
@change="togglePermissions">
{{ t('files_sharing', 'Read only') }}
</ActionRadio>
<ActionRadio :checked="share.permissions === publicUploadRWValue"
:value="publicUploadRWValue"
:disabled="saving"
@change="togglePermissions">{{ t('files_sharing', 'Allow upload and editing') }}</ActionCheckbox>
<ActionCheckbox :checked="share.permissions === publicUploadWValue"
:name="randomId"
@change="togglePermissions">
{{ t('files_sharing', 'Allow upload and editing') }}
</ActionRadio>
<ActionRadio :checked="share.permissions === publicUploadWValue"
:value="publicUploadWValue"
:disabled="saving"
:name="randomId"
class="sharing-entry__action--public-upload"
@change="togglePermissions">{{ t('files_sharing', 'File drop (upload only)') }}</ActionCheckbox>
@change="togglePermissions">
{{ t('files_sharing', 'File drop (upload only)') }}
</ActionRadio>
</template>

<!-- file -->
Expand Down Expand Up @@ -141,6 +163,7 @@
<ActionInput v-if="isPasswordProtected"
:class="{ error: errors.password}"
:disabled="saving"
:required="config.enforcePasswordForPublicLink"
:value="hasUnsavedPassword ? share.newPassword : '***************'"
icon="icon-password"
ref="password"
Expand All @@ -152,7 +175,7 @@
}"
:type="hasUnsavedPassword ? 'text': 'password'"
@update:value="onPasswordChange"
@submit="debounceQueueUpdate('password')">
@submit="onPasswordSubmit">
{{ t('files_sharing', 'Enter a password') }}
</ActionInput>

Expand Down Expand Up @@ -233,6 +256,7 @@ import axios from 'nextcloud-axios'

import ActionButton from 'nextcloud-vue/dist/Components/ActionButton'
import ActionCheckbox from 'nextcloud-vue/dist/Components/ActionCheckbox'
import ActionRadio from 'nextcloud-vue/dist/Components/ActionRadio'
import ActionInput from 'nextcloud-vue/dist/Components/ActionInput'
import ActionText from 'nextcloud-vue/dist/Components/ActionText'
import ActionTextEditable from 'nextcloud-vue/dist/Components/ActionTextEditable'
Expand All @@ -253,6 +277,7 @@ export default {
Actions,
ActionButton,
ActionCheckbox,
ActionRadio,
ActionInput,
ActionLink,
ActionText,
Expand Down Expand Up @@ -280,6 +305,15 @@ export default {
},

computed: {
/**
* Generate a unique random id for this SharingEntryLink only
* This allows ActionRadios to have the same name prop
* but not to impact others SharingEntryLink
*/
randomId() {
return Math.random().toString(27).substr(2)
},

/**
* Link share label
* TODO: allow editing
Expand Down Expand Up @@ -332,7 +366,7 @@ export default {
/**
* Pending data.
* If the share still doesn't have an id, it is not synced
* Therefore this is still not valid
* Therefore this is still not valid and requires user input
*/
pendingPassword() {
return this.config.enforcePasswordForPublicLink && this.share && !this.share.id
Expand All @@ -356,8 +390,10 @@ export default {
}
},

// if newPassword exists, but is empty, it means
// the user deleted the original password
hasUnsavedPassword() {
return this.share.newPassword && this.share.newPassword !== ''
return this.share.newPassword !== undefined
},

/**
Expand Down Expand Up @@ -405,6 +441,10 @@ export default {
externalActions() {
return this.ExternalLinkActions.actions
},

isPasswordPolicyEnabled() {
return typeof this.config.passwordPolicy === 'object'
}
},

methods: {
Expand Down Expand Up @@ -475,7 +515,7 @@ export default {
async pushNewLinkShare(share, update) {
try {
this.loading = true
this.open = false
this.errors = {}

const path = (this.fileInfo.path + '/' + this.fileInfo.name).replace('//', '/')
const newShare = await this.createShare({
Expand All @@ -490,6 +530,8 @@ export default {
// (currently not supported on create, only update)
})

this.open = false

console.debug('Link share created', newShare)

// if share already exists, copy link directly on next tick
Expand All @@ -515,7 +557,13 @@ export default {

} catch({ response }) {
const message = response.data.ocs.meta.message
this.onSyncError('pending', message)
if (message.match(/password/i)) {
this.onSyncError('password', message)
} else if (message.match(/date/i)) {
this.onSyncError('expireDate', message)
} else {
this.onSyncError('pending', message)
}
} finally {
this.loading = false
}
Expand All @@ -538,6 +586,7 @@ export default {
* @returns {string} a valid password
*/
async generatePassword() {
// password policy is enabled, let's request a pass
if (this.config.passwordPolicy.api && this.config.passwordPolicy.api.generate) {
try {
const request = await axios.get(this.config.passwordPolicy.api.generate)
Expand All @@ -548,6 +597,7 @@ export default {
console.info('Error generating password from password_policy', error);
}
}

// generate password of 10 length based on passwordSet
return Array(10).fill(0)
.reduce((prev, curr) => {
Expand All @@ -558,6 +608,11 @@ export default {
async copyLink() {
try {
await this.$copyText(this.shareLink)
this.$el.focus()
this.$nextTick(() => {
// focus and show the tooltip
this.$refs.copyButton.$el.focus()
})
this.copySuccess = true
this.copied = true
} catch (error) {
Expand All @@ -573,7 +628,7 @@ export default {
},

/**
* Update password and newPassword values
* Update newPassword values
* of share. If password is set but not newPassword
* then the user did not changed the password
* If both co-exists, the password have changed and
Expand All @@ -582,7 +637,6 @@ export default {
*/
onPasswordChange(password) {
this.$set(this.share, 'newPassword', password)
this.share.password = password
},

/**
Expand All @@ -593,25 +647,33 @@ export default {
*/
onPasswordDisable() {
this.share.password = ''

// reset password state after sync
this.$delete(this.share, 'newPassword')

// only update if valid share.
if (this.share.id) {
this.queueUpdate('password')
}
},

/**
* Menu have been closed.
* Menu have been closed or password has been submited.
* The only property that does not get
* synced automatically is the password
* So let's check if we have an unsaved
* password.
* expireDate is saved on datepicker pick
* or close.
*/
onMenuClose() {
onPasswordSubmit() {
if (this.hasUnsavedPassword) {
this.share.password = this.share.newPassword
this.queueUpdate('password')
}

// reset password state after sync
this.$delete(this.share, 'newPassword')
},

/**
Expand Down Expand Up @@ -673,23 +735,5 @@ export default {
.icon-checkmark-color {
opacity: 1;
}

&::v-deep .action-item__menu {
li.error {
animation: error 1s ease-in-out;
animation-iteration-count: 3;
}
}
}
@keyframes error {
0% {
background-color: var(--color-error)
}
50% {
background-color: var(--color-main-background)
}
100% {
background-color: var(--color-error)
}
}
</style>
12 changes: 1 addition & 11 deletions apps/files_sharing/src/mixins/SharesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export default {

// errors helpers
errors: {},
errorTimeout: null,

// component status toggles
loading: false,
Expand Down Expand Up @@ -230,16 +229,13 @@ export default {
const value = this.share[property]
this.updateQueue.add(async () => {
this.saving = true
this.errors = {}
try {
await this.updateShare(this.share.id, {
property,
value
})

// reset password state after sync
if (property === 'password') {
this.$delete(this.share, 'newPassword')
}
// clear any previous errors
this.$delete(this.errors, property)
} catch({ property, message }) {
Expand Down Expand Up @@ -269,12 +265,6 @@ export default {
// show error
this.$set(this.errors, property, message)

// Reset errors after 4 seconds
clearTimeout(this.errorTimeout)
this.errorTimeout = setTimeout(() => {
this.errors = {}
}, 4000)

if (this.$refs[property]) {
// focus if there is a focusable action element
const focusable = this.$refs[property].querySelector('.focusable')
Expand Down

0 comments on commit 00ff19d

Please sign in to comment.