Skip to content

Commit

Permalink
Init vue comments tab
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <[email protected]>
  • Loading branch information
skjnldsv committed Oct 4, 2020
1 parent df5bae2 commit 8073871
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 0 deletions.
62 changes: 62 additions & 0 deletions apps/comments/src/comments_tab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @copyright Copyright (c) 2020 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* 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 Vue from 'vue'
import { translate as t, translatePlural as n } from '@nextcloud/l10n'

import CommentsTab from './views/CommentsTab'

Vue.prototype.t = t
Vue.prototype.n = n

// Init Comments tab component
const View = Vue.extend(CommentsTab)
let TabInstance = null

window.addEventListener('DOMContentLoaded', function() {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
id: 'comments',
name: t('comments', 'Comments'),
icon: 'icon-comment',

async mount(el, fileInfo, context) {
if (TabInstance) {
TabInstance.$destroy()
}
TabInstance = new View({
// Better integration with vue parent component
parent: context,
})
// Only mount after we have all the info we need
await TabInstance.update(fileInfo)
TabInstance.$mount(el)
},
update(fileInfo) {
TabInstance.update(fileInfo)
},
destroy() {
TabInstance.$destroy()
TabInstance = null
},
}))
}
})
Empty file.
40 changes: 40 additions & 0 deletions apps/comments/src/services/DavClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @copyright Copyright (c) 2019 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* 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 webdav from 'webdav'
import axios from '@nextcloud/axios'
import { getRootPath, getToken, isPublic } from '../utils/davUtils'

// Add this so the server knows it is an request from the browserg
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'

// force our axios
const patcher = webdav.getPatcher()
patcher.patch('request', axios)

// init webdav client
const client = webdav.createClient(getRootPath(), isPublic()
? { username: getToken(), password: '' }
: {}
)

export default client
122 changes: 122 additions & 0 deletions apps/comments/src/utils/fileUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* @copyright Copyright (c) 2019 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* 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 camelcase from 'camelcase'
import { isNumber } from './numberUtil'

/**
* Get an url encoded path
*
* @param {String} path the full path
* @returns {string} url encoded file path
*/
const encodeFilePath = function(path) {
const pathSections = (path.startsWith('/') ? path : `/${path}`).split('/')
let relativePath = ''
pathSections.forEach((section) => {
if (section !== '') {
relativePath += '/' + encodeURIComponent(section)
}
})
return relativePath
}

/**
* Extract dir and name from file path
*
* @param {String} path the full path
* @returns {String[]} [dirPath, fileName]
*/
const extractFilePaths = function(path) {
const pathSections = path.split('/')
const fileName = pathSections[pathSections.length - 1]
const dirPath = pathSections.slice(0, pathSections.length - 1).join('/')
return [dirPath, fileName]
}

/**
* Sorting comparison function
*
* @param {Object} fileInfo1 file 1 fileinfo
* @param {Object} fileInfo2 file 2 fileinfo
* @param {string} key key to sort with
* @param {boolean} [asc=true] sort ascending?
* @returns {number}
*/
const sortCompare = function(fileInfo1, fileInfo2, key, asc = true) {

if (fileInfo1.isFavorite && !fileInfo2.isFavorite) {
return -1
} else if (!fileInfo1.isFavorite && fileInfo2.isFavorite) {
return 1
}

// if this is a number, let's sort by integer
if (isNumber(fileInfo1[key]) && isNumber(fileInfo2[key])) {
return Number(fileInfo1[key]) - Number(fileInfo2[key])
}

// else we sort by string, so let's sort directories first
if (fileInfo1.type === 'directory' && fileInfo2.type !== 'directory') {
return -1
} else if (fileInfo1.type !== 'directory' && fileInfo2.type === 'directory') {
return 1
}

// finally sort by name
return asc
? fileInfo1[key].localeCompare(fileInfo2[key], OC.getLanguage())
: -fileInfo1[key].localeCompare(fileInfo2[key], OC.getLanguage())
}

/**
* Generate a fileinfo object based on the full dav properties
* It will flatten everything and put all keys to camelCase
*
* @param {Object} obj the object
* @returns {Object}
*/
const genFileInfo = function(obj) {
const fileInfo = {}

Object.keys(obj).forEach(key => {
const data = obj[key]

// flatten object if any
if (!!data && typeof data === 'object' && !Array.isArray(data)) {
Object.assign(fileInfo, genFileInfo(data))
} else {
// format key and add it to the fileInfo
if (data === 'false') {
fileInfo[camelcase(key)] = false
} else if (data === 'true') {
fileInfo[camelcase(key)] = true
} else {
fileInfo[camelcase(key)] = isNumber(data)
? Number(data)
: data
}
}
})
return fileInfo
}

export { encodeFilePath, extractFilePaths, sortCompare, genFileInfo }
104 changes: 104 additions & 0 deletions apps/comments/src/views/CommentsTab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!--
- @copyright Copyright (c) 2020 John Molakvoæ <[email protected]>
-
- @author John Molakvoæ <[email protected]>
-
- @license GNU AGPL version 3 or any later version
-
- 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/>.
-
-->

<template>
<div :class="{ 'icon-loading': loading }">
<!-- error message -->
<div v-if="error" class="emptycontent">
<div class="icon icon-error" />
<h2>{{ error }}</h2>
</div>

<!-- comments -->
<template v-else>
<EmptyContent icon="icon-comment">
{{ t('comments', 'No comments yet, start the conversation!') }}
</EmptyContent>
</template>
</div>
</template>

<script>
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
import axios from '@nextcloud/axios'
export default {
name: 'CommentsTab',
components: {
Avatar,
EmptyContent,
},
data() {
return {
error: '',
loading: true,
fileInfo: null,
comments: [],
}
},
computed: {
},
methods: {
/**
* Update current fileInfo and fetch new data
* @param {Object} fileInfo the current file FileInfo
*/
async update(fileInfo) {
this.fileInfo = fileInfo
this.resetState()
this.getShares()
},
/**
* Get the existing shares infos
*/
async getComments() {
try {
this.loading = true
// Fetch comments
} catch (error) {
this.error = t('comments', 'Unable to load the comments list')
console.error('Error loading the comments list', error)
} finally {
this.loading = false
}
},
/**
* Reset the current view to its default state
*/
resetState() {
this.loading = true
this.error = ''
this.comments = []
},
},
}
</script>

0 comments on commit 8073871

Please sign in to comment.