Skip to content

Commit

Permalink
Merge pull request #787 from nextcloud/enh/simple-link-input
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusknorr authored Aug 30, 2024
2 parents ee0ffa4 + ef6ea7e commit 0fee7b8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 30 deletions.
6 changes: 2 additions & 4 deletions cypress/e2e/column-text-link.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ describe('Test column text-link', () => {

cy.loadTable('Test text-link')
cy.get('.NcTable').contains('Create row').click({ force: true })
cy.get('.modal__content .slot input').first().type('https://nextcloud.com').tick(500)
cy.get('.icon-label-container .labels').contains('https://nextcloud.com').click()
cy.get('.modal__content .slot input').first().type('https://nextcloud.com')

cy.intercept({ method: 'GET', url: '**/search/providers/files/*' }).as('filesResults')
cy.get('.modal__content .slot input').eq(1).type('pdf').tick(500)
Expand All @@ -58,8 +57,7 @@ describe('Test column text-link', () => {
cy.loadTable('Test text-link')
cy.get('.NcTable tr td button').click({ force: true })

cy.get('.modal__content .slot input').first().clear().type('https://github.com').tick(500)
cy.get('[data-cy*="github"]').click()
cy.get('.modal__content .slot input').first().clear().type('https://github.com')

cy.get('.modal__content .slot input').eq(1).type('photo-test').tick(500)
cy.get('[data-cy*="photo-test"]').first().click()
Expand Down
4 changes: 3 additions & 1 deletion cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ Cypress.Commands.add('createTextLinkColumn', (title, ressourceProvider, isFirstC
cy.get('.typeSelection span').contains('Url', { matchCase: false }).click()
cy.get('.typeSelection span').contains('Files').click()
// TODO is the contacts search provider deactivated by default beginning with nc28
// cy.get('.typeSelection span label').contains('Contacts').click()
if (['stable27'].includes(Cypress.env('ncVersion'))) {
cy.get('.typeSelection span').contains('Contacts').click()
}

ressourceProvider.forEach(provider =>
cy.get('.typeSelection span').contains(provider, { matchCase: false }).click(),
Expand Down
22 changes: 4 additions & 18 deletions src/modules/sidebar/sections/SidebarIntegration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,18 @@
import { mapGetters, mapState } from 'vuex'
import { generateUrl } from '@nextcloud/router'
import permissionsMixin from '../../../shared/components/ncTable/mixins/permissionsMixin.js'
import copyToClipboard from '../../../shared/mixins/copyToClipboard.js'
import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js'
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
import { showError, showSuccess } from '@nextcloud/dialogs'
export default {
components: {
NcInputField,
ContentCopy,
},
mixins: [permissionsMixin],
mixins: [permissionsMixin, copyToClipboard],
data() {
return {
Expand All @@ -80,22 +81,7 @@ export default {
},
methods: {
copyUrl() {
if (navigator?.clipboard) {
navigator.clipboard.writeText(this.apiEndpointUrl).then(function() {
showSuccess(t('files', 'Integration URL copied to clipboard'))
}, function(err) {
showError(t('files', 'Clipboard is not available'))
console.error('Async: Could not copy text: ', err)
})
} else {
try {
document.querySelector('input#urlTextField').select()
document.execCommand('copy')
showSuccess(t('files', 'Integration URL copied to clipboard'))
} catch (e) {
showError(t('files', 'Clipboard is not available'))
}
}
this.copyToClipboard(this.apiEndpointUrl, false)
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
{{ t('tables', 'You can not insert any links in this field. Please configure at least one link provider in the column configuration.') }}
</NcNoteCard>
</div>
<div class="col-4">
<NcSelect v-model="localValue"
<div class="link-input">
<NcTextField v-if="isPlainUrl" :value.sync="plainLink" :placeholder="t('tables', 'URL')" />
<NcSelect v-else v-model="localValue"
:options="results"
:clearable="true"
label="title"
Expand All @@ -22,35 +23,58 @@
<LinkWidget :thumbnail-url="props.thumbnailUrl" :icon-url="props.icon" :title="props.title" :subline="props.subline" :icon-size="40" />
</template>
<template #selected-option="props">
<LinkWidget :thumbnail-url="props.thumbnailUrl" :icon-url="props.icon" :title="props.title" :subline="props.subline" :icon-size="40" />
<LinkWidget :thumbnail-url="props.thumbnailUrl" :icon-url="props.icon" :title="props.title" :icon-size="24" />
</template>
</NcSelect>
<NcButton type="tertiary" :disabled="!localValue" :title="t('tables', 'Copy link')" @click="copyLink">
<template #icon>
<ContentCopy v-if="!copied" :size="20" />
<ClipboardCheckMultipleOutline v-else :size="20" />
</template>
</NcButton>
<NcButton type="tertiary" :disabled="!localValue" :title="t('tables', 'Open link')" @click="openLink">
<template #icon>
<OpenInNew :size="20" />
</template>
</NcButton>
</div>
<NcReferenceList :text="localValue?.value" :limit="1" :interactive="false" />
</div>
</RowFormWrapper>
</template>
<script>
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
import ClipboardCheckMultipleOutline from 'vue-material-design-icons/ClipboardCheckMultipleOutline.vue'
import OpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import { NcReferenceList } from '@nextcloud/vue/dist/Components/NcRichText.js'
import RowFormWrapper from './RowFormWrapper.vue'
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import displayError from '../../../../utils/displayError.js'
import { NcNoteCard, NcSelect } from '@nextcloud/vue'
import { NcButton, NcTextField, NcNoteCard, NcSelect } from '@nextcloud/vue'
import debounce from 'debounce'
import generalHelper from '../../../../mixins/generalHelper.js'
import copyToClipboard from '../../../../mixins/copyToClipboard.js'
import LinkWidget from '../LinkWidget.vue'
import { translate as t } from '@nextcloud/l10n'
export default {
components: {
ContentCopy,
ClipboardCheckMultipleOutline,
OpenInNew,
NcButton,
NcNoteCard,
RowFormWrapper,
NcSelect,
NcReferenceList,
NcTextField,
RowFormWrapper,
LinkWidget,
},
mixins: [generalHelper],
mixins: [generalHelper, copyToClipboard],
props: {
column: {
Expand All @@ -69,10 +93,24 @@ export default {
results: [],
term: '',
providerLoading: {},
copied: false,
}
},
computed: {
plainLink: {
get() {
return this.localValue?.value ?? ''
},
set(v) {
this.$emit('update:value', JSON.stringify({
title: v,
subline: t('tables', 'URL'),
providerId: 'url',
value: v,
}))
},
},
localValue: {
get() {
// if we got an old value (string not object as json)
Expand All @@ -95,6 +133,9 @@ export default {
this.$emit('update:value', value)
},
},
isPlainUrl() {
return this.providers?.length === 1 && this.providers[0] === 'url'
},
isLoadingResults() {
for (const [key, value] of Object.entries(this.providerLoading)) {
console.debug('is still loading results at least for: ' + key, value)
Expand Down Expand Up @@ -155,7 +196,9 @@ export default {
this.removeResultsByProviderId(providerId)
if (providerId === 'url') {
this.addUrlResult(term)
if (this.isValidUrl(term)) {
this.addUrlResult(term)
}
this.setProviderLoading(providerId, false)
return
}
Expand Down Expand Up @@ -186,6 +229,14 @@ export default {
this.setProviderLoading(providerId, false)
},
isValidUrl(string) {
try {
return new URL(string)
} catch (err) {
return false
}
},
addUrlResult(term) {
this.results.push({
title: term,
Expand All @@ -198,6 +249,42 @@ export default {
removeResultsByProviderId(providerId) {
this.results = this.results.filter(item => item.providerId !== providerId)
},
copyLink() {
if (this.localValue) {
if (this.copied !== false) {
clearTimeout(this.copied)
}
this.copied = this.copyToClipboard(this.localValue.value)
? setTimeout(() => {
this.copied = false
}, 3000)
: false
}
},
openLink() {
if (this.localValue) {
window.open(this.localValue.value, '_blank')
}
},
},
}
</script>
<style lang="scss" scoped>
.link-input {
display: flex;
align-items: center;
margin-bottom: var(--default-grid-baseline);
:deep(.v-select:not(.vs--open) .vs__search) {
position: absolute;
}
:deep(.vs__selected) {
flex-grow: 1;
height: auto !important;
}
}
</style>
30 changes: 30 additions & 0 deletions src/shared/mixins/copyToClipboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { showError, showSuccess } from '@nextcloud/dialogs'

export default {
methods: {
async copyToClipboard(content, silent = true) {
try {
if (navigator?.clipboard) {
await navigator.clipboard.writeText(content)
} else {
throw new Error('Clipboard is not available')
}

if (!silent) {
showSuccess(t('files', 'Copied to clipboard.'))
}
return true
} catch (e) {
console.error('Error copying to clipboard', e)
if (!silent) {
showError(t('files', 'Clipboard is not available'))
}
}
},
},
}

0 comments on commit 0fee7b8

Please sign in to comment.