mirror of https://github.com/nocodb/nocodb
Pranav C
2 years ago
44 changed files with 3345 additions and 74 deletions
@ -0,0 +1,123 @@ |
|||||||
|
<template> |
||||||
|
<div |
||||||
|
class="d-flex align-center img-container d-100 h-100" |
||||||
|
v-on="$listeners" |
||||||
|
@dragover.prevent="dragOver = true" |
||||||
|
@dragenter.prevent="dragOver = true" |
||||||
|
@dragexit="dragOver = false" |
||||||
|
@dragleave="dragOver = false" |
||||||
|
@dragend="dragOver = false" |
||||||
|
@drop.prevent |
||||||
|
> |
||||||
|
<div v-if="dragOver" class="drop-overlay"> |
||||||
|
<div> |
||||||
|
<v-icon small> |
||||||
|
mdi-cloud-upload-outline |
||||||
|
</v-icon> |
||||||
|
<span class="caption font-weight-bold">Drop here</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<template v-if="localState"> |
||||||
|
<div v-for="item in localState" :key="item.title" class="thumbnail d-flex align-center justify-center"> |
||||||
|
<v-lazy class="d-flex align-center justify-center"> |
||||||
|
<v-tooltip bottom> |
||||||
|
<template #activator="{on}"> |
||||||
|
<img v-if="isImage(item.title)" alt="#" :src="item.url" v-on="on"> |
||||||
|
<v-icon v-else-if="item.icon" size="33" v-on="on"> |
||||||
|
{{ item.icon }} |
||||||
|
</v-icon> |
||||||
|
<v-icon v-else size="33" v-on="on"> |
||||||
|
mdi-file |
||||||
|
</v-icon> |
||||||
|
</template> |
||||||
|
<span>{{ item.title }}</span> |
||||||
|
</v-tooltip> |
||||||
|
</v-lazy> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { isImage } from '@/components/project/spreadsheet/helpers/imageExt' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'AttachmentCell', |
||||||
|
props: ['value', 'column'], |
||||||
|
data: () => ({ |
||||||
|
dragOver: false |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
localState() { |
||||||
|
try { |
||||||
|
return JSON.parse(this.value) || [] |
||||||
|
} catch (e) { |
||||||
|
return [] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
isImage |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.img-container { |
||||||
|
margin: 0 -2px; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.thumbnail { |
||||||
|
height: 29px; |
||||||
|
width: 29px; |
||||||
|
margin: 2px; |
||||||
|
border-radius: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
.thumbnail img { |
||||||
|
max-height: 29px; |
||||||
|
max-width: 29px; |
||||||
|
} |
||||||
|
|
||||||
|
.drop-overlay { |
||||||
|
z-index: 5; |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 5px; |
||||||
|
background: #aaaaaa44; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
pointer-events: none; |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,11 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import { inject } from '@vue/runtime-core' |
||||||
|
|
||||||
|
const value = inject<boolean | number>('value') |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div class="d-flex align-center"> |
||||||
|
<input v-model="value" type="checkbox" :disabled="true"> |
||||||
|
</div> |
||||||
|
</template> |
@ -0,0 +1,40 @@ |
|||||||
|
<template> |
||||||
|
<a v-if="value">{{ currency }}</a> |
||||||
|
<span v-else /> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'CurrencyCell', |
||||||
|
props: { |
||||||
|
column: Object, |
||||||
|
value: [String, Number] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
currency() { |
||||||
|
try { |
||||||
|
return isNaN(this.value) |
||||||
|
? this.value |
||||||
|
: new Intl.NumberFormat(this.currencyMeta.currency_locale || 'en-US', |
||||||
|
{ style: 'currency', currency: this.currencyMeta.currency_code || 'USD' }) |
||||||
|
.format(this.value) |
||||||
|
} catch (e) { |
||||||
|
return this.value |
||||||
|
} |
||||||
|
}, |
||||||
|
currencyMeta() { |
||||||
|
return { |
||||||
|
currency_locale: 'en-US', |
||||||
|
currency_code: 'USD', |
||||||
|
...(this.column && this.column.meta |
||||||
|
? this.column.meta |
||||||
|
: {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,21 @@ |
|||||||
|
<template> |
||||||
|
<span>{{ date }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import dayjs from 'dayjs' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DateCell', |
||||||
|
props: ['value'], |
||||||
|
computed: { |
||||||
|
date() { |
||||||
|
return (/^\d+$/.test(this.value) ? dayjs(+this.value) : dayjs(this.value)).format('YYYY-MM-DD') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,21 @@ |
|||||||
|
<template> |
||||||
|
<span>{{ dateTime }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import dayjs from 'dayjs' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DateTimeCell', |
||||||
|
props: ['value'], |
||||||
|
computed: { |
||||||
|
dateTime() { |
||||||
|
return !this.value ? this.value : (/^\d+$/.test(this.value) ? dayjs(+this.value) : dayjs(this.value)).format('YYYY-MM-DD HH:mm') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,69 @@ |
|||||||
|
<template> |
||||||
|
<input |
||||||
|
v-model="localValue" |
||||||
|
:placeholder="durationPlaceholder" |
||||||
|
readonly |
||||||
|
> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { durationOptions, convertMS2Duration } from '~/helpers/durationHelper' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DurationCell', |
||||||
|
props: { |
||||||
|
column: Object, |
||||||
|
value: [String, Number] |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
showWarningMessage: false, |
||||||
|
localValue: null |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
durationPlaceholder() { |
||||||
|
return durationOptions[this.column?.meta?.duration || 0].title |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'column.meta.duration'(newValue, oldValue) { |
||||||
|
if (oldValue !== newValue) { |
||||||
|
this.localValue = convertMS2Duration(this.value, newValue) |
||||||
|
} |
||||||
|
}, |
||||||
|
value(val, oldVal) { |
||||||
|
this.localValue = convertMS2Duration(val !== oldVal && (!val && val !== 0) ? oldVal : val, this.column?.meta?.duration || 0) |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
this.localValue = convertMS2Duration(this.value, this.column?.meta?.duration || 0) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
||||||
|
|
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Wing-Kam Wong <wingkwong.code@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,22 @@ |
|||||||
|
<template> |
||||||
|
<a v-if="isEmail" :href="`mailto:${value}`" target="_blank">{{ value }}</a> |
||||||
|
<span v-else>{{ value }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { isEmail } from '~/helpers' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'EmailCell', |
||||||
|
props: ['value'], |
||||||
|
computed: { |
||||||
|
isEmail() { |
||||||
|
return isEmail(this.value || '') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,31 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import type { ColumnType } from 'nocodb-sdk' |
||||||
|
import { inject } from 'vue' |
||||||
|
import { enumColor } from '~/composables/colors' |
||||||
|
|
||||||
|
const colors = enumColor.light |
||||||
|
|
||||||
|
const value = inject('value') |
||||||
|
const column = inject<ColumnType>('column') |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div> |
||||||
|
<span |
||||||
|
v-for="v in [(value || '').replace(/\\'/g, '\'').replace(/^'|'$/g, '')]" |
||||||
|
:key="v" |
||||||
|
:style="{ |
||||||
|
background: colors[v], |
||||||
|
}" |
||||||
|
class="set-item ma-1 py-1 px-3" |
||||||
|
>{{ v }}</span> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.set-item { |
||||||
|
display: inline-block; |
||||||
|
border-radius: 25px; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,14 @@ |
|||||||
|
<template> |
||||||
|
<pre class="text-left caption">{{ value }}</pre> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'JsonCell', |
||||||
|
props: ['value'] |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,68 @@ |
|||||||
|
<script> |
||||||
|
// import colors from '@/mixins/colors' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'SetListCell', |
||||||
|
// mixins: [colors], |
||||||
|
props: ['value', 'column'], |
||||||
|
computed: { |
||||||
|
setValues() { |
||||||
|
if (this.column && this.column.dtxp) |
||||||
|
return this.column.dtxp.split(',').map(v => v.replace(/\\'/g, '\'').replace(/^'|'$/g, '')) |
||||||
|
|
||||||
|
return [] |
||||||
|
}, |
||||||
|
selectedValues() { |
||||||
|
return this.value ? this.value.split(',').map(v => v.replace(/\\'/g, '\'').replace(/^'|'$/g, '')) : [] |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div> |
||||||
|
<v-chip |
||||||
|
v-for="v in selectedValues" |
||||||
|
v-show="v || setValues.includes(v)" |
||||||
|
:key="v" |
||||||
|
small |
||||||
|
:color="colors[setValues.indexOf(v) % colors.length]" |
||||||
|
class="set-item ma-1 py-1 px-3" |
||||||
|
> |
||||||
|
{{ v }} |
||||||
|
</v-chip> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
/* |
||||||
|
.set-item { |
||||||
|
display: inline-block; |
||||||
|
border-radius: 25px; |
||||||
|
white-space: nowrap; |
||||||
|
}*/ |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,19 @@ |
|||||||
|
<template> |
||||||
|
<span>{{ time }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'TimeCell', |
||||||
|
props: ['value'], |
||||||
|
computed: { |
||||||
|
time() { |
||||||
|
return typeof this.value === 'string' ? this.value.replace(/(\d)T(?=\d)/, '$1 ') : this.value |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,23 @@ |
|||||||
|
<template> |
||||||
|
<a v-if="isValid" :href="value" target="_blank">{{ value }}</a> |
||||||
|
<span v-else>{{ value }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
|
||||||
|
import { isValidURL } from '~/helpers' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'UrlCell', |
||||||
|
props: ['value'], |
||||||
|
computed: { |
||||||
|
isValid() { |
||||||
|
return this.value && isValidURL(this.value) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,85 @@ |
|||||||
|
<template> |
||||||
|
<div class="d-flex align-center " :class="{'justify-center':!isForm,'nc-cell-hover-show': !localState}"> |
||||||
|
<v-icon small :color="checkboxMeta.color" @click="toggle"> |
||||||
|
{{ localState ? checkedIcon :uncheckedIcon }} |
||||||
|
</v-icon> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'BooleanCell', |
||||||
|
props: { |
||||||
|
column: Object, |
||||||
|
value: [String, Number, Boolean], |
||||||
|
isForm: Boolean, |
||||||
|
readOnly: Boolean |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
|
||||||
|
checkedIcon() { |
||||||
|
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.checked) || 'mdi-check-bold' |
||||||
|
}, |
||||||
|
uncheckedIcon() { |
||||||
|
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.unchecked) || 'mdi-crop-square' |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
return $listeners |
||||||
|
}, |
||||||
|
checkboxMeta() { |
||||||
|
return { |
||||||
|
icon: { |
||||||
|
checked: 'mdi-check-circle-outline', |
||||||
|
unchecked: 'mdi-checkbox-blank-circle-outline' |
||||||
|
}, |
||||||
|
color: 'primary', |
||||||
|
...(this.column && this.column.meta |
||||||
|
? this.column.meta |
||||||
|
: {}) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
toggle() { |
||||||
|
this.localState = !this.localState |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,92 @@ |
|||||||
|
<template> |
||||||
|
<v-menu> |
||||||
|
<template #activator="{on}"> |
||||||
|
<input :value="date" class="value" v-on="on"> |
||||||
|
</template> |
||||||
|
<v-date-picker |
||||||
|
v-model="localState" |
||||||
|
flat |
||||||
|
@click.native.stop |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
</v-menu> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import dayjs from 'dayjs' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DatePickerCell', |
||||||
|
props: { |
||||||
|
value: [String, Date] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
if (!this.value || !dayjs(this.value).isValid()) { return undefined } |
||||||
|
|
||||||
|
return (/^\d+$/.test(this.value) ? dayjs(+this.value) : dayjs(this.value)).format('YYYY-MM-DD') |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
if (dayjs(val).isValid()) { |
||||||
|
this.$emit('input', val && dayjs(val).format('YYYY-MM-DD')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
date() { |
||||||
|
if (!this.value || this.localState) { |
||||||
|
return this.localState |
||||||
|
} |
||||||
|
return 'Invalid Date' |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
if (this.$el && this.$el.$el) { |
||||||
|
this.$el.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.value { |
||||||
|
width: 100%; |
||||||
|
min-height: 20px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,132 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<div v-show="!showMessage"> |
||||||
|
<v-datetime-picker |
||||||
|
ref="picker" |
||||||
|
v-model="localState" |
||||||
|
class="caption xc-date-time-picker" |
||||||
|
:text-field-props="{ |
||||||
|
class:'caption mt-0 pt-0', |
||||||
|
flat:true, |
||||||
|
solo:true, |
||||||
|
dense:true, |
||||||
|
hideDetails:true |
||||||
|
}" |
||||||
|
:time-picker-props="{ |
||||||
|
format:'24hr' |
||||||
|
}" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div v-show="showMessage" class="edit-warning" @dblclick="$refs.picker.display = true"> |
||||||
|
<!-- TODO: i18n --> |
||||||
|
ERR: Couldn't parse {{ this.value }} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
|
||||||
|
import dayjs from 'dayjs' |
||||||
|
import utc from 'dayjs/plugin/utc' |
||||||
|
|
||||||
|
dayjs.extend(utc) |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DateTimePickerCell', |
||||||
|
props: { |
||||||
|
value: [String, Date, Number], ignoreFocus: Boolean |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
showMessage: false |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
isMysql() { |
||||||
|
return ['mysql', 'mysql2'].indexOf(this.$store.getters['project/GtrClientType']) |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
if (!this.value) { |
||||||
|
return this.value |
||||||
|
} |
||||||
|
const d = (/^\d+$/.test(this.value) ? dayjs(+this.value) : dayjs(this.value)) |
||||||
|
if (d.isValid()) { |
||||||
|
this.showMessage = false |
||||||
|
return d.format('YYYY-MM-DD HH:mm') |
||||||
|
} else { |
||||||
|
this.showMessage = true |
||||||
|
} |
||||||
|
}, |
||||||
|
set(value) { |
||||||
|
if (this.isMysql) { |
||||||
|
this.$emit('input', value && dayjs(value).format('YYYY-MM-DD HH:mm:ss')) |
||||||
|
} else { |
||||||
|
this.$emit('input', value && dayjs(value).format('YYYY-MM-DD HH:mm:ssZ')) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
// $listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// listen dialog click:outside event and save on close |
||||||
|
if (this.$refs.picker && this.$refs.picker.$children && this.$refs.picker.$children[0]) { |
||||||
|
this.$refs.picker.$children[0].$on('click:outside', () => { |
||||||
|
this.$refs.picker.okHandler() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.ignoreFocus) { |
||||||
|
this.$refs.picker.display = true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
/deep/ .v-input, /deep/ .v-text-field { |
||||||
|
margin-top: 0 !important; |
||||||
|
padding-top: 0 !important; |
||||||
|
font-size: inherit !important; |
||||||
|
} |
||||||
|
|
||||||
|
.edit-warning { |
||||||
|
padding: 10px; |
||||||
|
text-align: left; |
||||||
|
color: #E65100; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,139 @@ |
|||||||
|
<template> |
||||||
|
<div class="duration-cell-wrapper"> |
||||||
|
<input |
||||||
|
ref="durationInput" |
||||||
|
v-model="localState" |
||||||
|
:placeholder="durationPlaceholder" |
||||||
|
@blur="onBlur" |
||||||
|
@keypress="checkDurationFormat($event)" |
||||||
|
@keydown.enter="isEdited && $emit('input', durationInMS)" |
||||||
|
v-on="parentListeners" |
||||||
|
> |
||||||
|
<div v-if="showWarningMessage == true" class="duration-warning"> |
||||||
|
<!-- TODO: i18n --> |
||||||
|
Please enter a number |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { durationOptions, convertMS2Duration, convertDurationToSeconds } from '~/helpers/durationHelper' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'DurationCell', |
||||||
|
props: { |
||||||
|
column: Object, |
||||||
|
value: [Number, String], |
||||||
|
readOnly: Boolean |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
// flag to determine to show warning message or not |
||||||
|
showWarningMessage: false, |
||||||
|
// duration in milliseconds |
||||||
|
durationInMS: null, |
||||||
|
// check if the cell is edited or not |
||||||
|
isEdited: false |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return convertMS2Duration(this.value, this.durationType) |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.isEdited = true |
||||||
|
const res = convertDurationToSeconds(val, this.durationType) |
||||||
|
if (res._isValid) { |
||||||
|
this.durationInMS = res._sec |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
durationPlaceholder() { |
||||||
|
return durationOptions[this.durationType].title |
||||||
|
}, |
||||||
|
durationType() { |
||||||
|
return this.column?.meta?.duration || 0 |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
window.addEventListener('keypress', (_) => { |
||||||
|
if (this.$refs.durationInput) { |
||||||
|
this.$refs.durationInput.focus() |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
checkDurationFormat(evt) { |
||||||
|
evt = evt || window.event |
||||||
|
const charCode = (evt.which) ? evt.which : evt.keyCode |
||||||
|
// ref: http://www.columbia.edu/kermit/ascii.html |
||||||
|
const PRINTABLE_CTL_RANGE = charCode > 31 |
||||||
|
const NON_DIGIT = charCode < 48 || charCode > 57 |
||||||
|
const NON_COLON = charCode !== 58 |
||||||
|
const NON_PERIOD = charCode !== 46 |
||||||
|
if (PRINTABLE_CTL_RANGE && NON_DIGIT && NON_COLON && NON_PERIOD) { |
||||||
|
this.showWarningMessage = true |
||||||
|
evt.preventDefault() |
||||||
|
} else { |
||||||
|
this.showWarningMessage = false |
||||||
|
// only allow digits, '.' and ':' (without quotes) |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
onBlur() { |
||||||
|
if (this.isEdited) { |
||||||
|
this.$emit('input', this.durationInMS) |
||||||
|
} |
||||||
|
this.isEdited = false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
.duration-cell-wrapper { |
||||||
|
padding: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.duration-warning { |
||||||
|
text-align: left; |
||||||
|
margin-top: 10px; |
||||||
|
color: #E65100; |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Wing-Kam Wong <wingkwong.code@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,599 @@ |
|||||||
|
<template> |
||||||
|
<div |
||||||
|
class="main h-100" |
||||||
|
@dragover.prevent="dragOver = true" |
||||||
|
@dragenter.prevent="dragOver = true" |
||||||
|
@dragexit="dragOver = false" |
||||||
|
@dragleave="dragOver = false" |
||||||
|
@dragend="dragOver = false" |
||||||
|
@drop.prevent.stop="onFileDrop" |
||||||
|
> |
||||||
|
<div v-show="(isForm || _isUIAllowed('tableAttachment')) && dragOver" class="drop-overlay"> |
||||||
|
<div> |
||||||
|
<v-icon small> |
||||||
|
mdi-cloud-upload-outline |
||||||
|
</v-icon> |
||||||
|
<span class="caption font-weight-bold">Drop here</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="d-flex align-center img-container"> |
||||||
|
<div class="d-flex no-overflow"> |
||||||
|
<div |
||||||
|
v-for="(item,i) in (isPublicForm ? localFilesState : localState)" |
||||||
|
:key="item.url || item.title" |
||||||
|
class="thumbnail align-center justify-center d-flex" |
||||||
|
> |
||||||
|
<v-tooltip bottom> |
||||||
|
<template #activator="{on}"> |
||||||
|
<v-img |
||||||
|
v-if="isImage(item.title, item.mimetype)" |
||||||
|
lazy-src="https://via.placeholder.com/60.png?text=Loading..." |
||||||
|
alt="#" |
||||||
|
max-height="99px" |
||||||
|
contain |
||||||
|
:src="item.url || item.data" |
||||||
|
v-on="on" |
||||||
|
@click="selectImage(item.url || item.data, i)" |
||||||
|
> |
||||||
|
<template #placeholder> |
||||||
|
<v-skeleton-loader |
||||||
|
type="image" |
||||||
|
:height="active ? 33 : 22" |
||||||
|
:width="active ? 33 : 22" |
||||||
|
/> |
||||||
|
</template> |
||||||
|
</v-img> |
||||||
|
<v-icon |
||||||
|
v-else-if="item.icon" |
||||||
|
:size="active ? 33 : 22" |
||||||
|
v-on="on" |
||||||
|
@click="openUrl(item.url || item.data,'_blank')" |
||||||
|
> |
||||||
|
{{ |
||||||
|
item.icon |
||||||
|
}} |
||||||
|
</v-icon> |
||||||
|
<v-icon v-else :size="active ? 33 : 22" v-on="on" @click="openUrl(item.url|| item.data,'_blank')"> |
||||||
|
mdi-file |
||||||
|
</v-icon> |
||||||
|
</template> |
||||||
|
<span>{{ item.title }}</span> |
||||||
|
</v-tooltip> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div |
||||||
|
v-if="isForm || active && !isPublicGrid && !isLocked" |
||||||
|
class="add d-flex align-center justify-center px-1 nc-attachment-add" |
||||||
|
@click="addFile" |
||||||
|
> |
||||||
|
<v-icon v-if="uploading" small color="primary" class="nc-attachment-add-spinner"> |
||||||
|
mdi-loading mdi-spin |
||||||
|
</v-icon> |
||||||
|
<v-btn |
||||||
|
v-else-if="isForm" |
||||||
|
outlined |
||||||
|
x-small |
||||||
|
color="" |
||||||
|
text |
||||||
|
class="nc-attachment-add-btn" |
||||||
|
> |
||||||
|
<v-icon x-small color=""> |
||||||
|
mdi-plus |
||||||
|
</v-icon> |
||||||
|
Attachment |
||||||
|
</v-btn> |
||||||
|
<v-icon |
||||||
|
v-else-if="_isUIAllowed('tableAttachment')" |
||||||
|
v-show="active" |
||||||
|
small |
||||||
|
color="primary nc-attachment-add-icon" |
||||||
|
> |
||||||
|
mdi-plus |
||||||
|
</v-icon> |
||||||
|
</div> |
||||||
|
|
||||||
|
<v-spacer /> |
||||||
|
|
||||||
|
<v-icon class="expand-icon mr-1" x-small color="primary" @click.stop="dialog = true"> |
||||||
|
mdi-arrow-expand |
||||||
|
</v-icon> |
||||||
|
<input ref="file" type="file" multiple class="d-none" @change="onFileSelection"> |
||||||
|
</div> |
||||||
|
<v-dialog |
||||||
|
v-if="dialog" |
||||||
|
v-model="dialog" |
||||||
|
width="800" |
||||||
|
> |
||||||
|
<v-card class="h-100 images-modal"> |
||||||
|
<v-card-text class="h-100 backgroundColor"> |
||||||
|
<div class="d-flex mx-2"> |
||||||
|
<v-btn |
||||||
|
v-if="(isForm || _isUIAllowed('tableAttachment')) && !isPublicGrid && !isLocked" |
||||||
|
small |
||||||
|
class="my-4 " |
||||||
|
:loading="uploading" |
||||||
|
@click="addFile" |
||||||
|
> |
||||||
|
<v-icon small class="mr-2"> |
||||||
|
mdi-link-variant |
||||||
|
</v-icon> |
||||||
|
<span class="caption">Attach File</span> |
||||||
|
</v-btn> |
||||||
|
|
||||||
|
<!-- <v-text-field v-model="urlString" @keypress.enter="uploadByUrl" />--> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="d-flex flex-wrap h-100"> |
||||||
|
<v-container fluid style="max-height:calc(90vh - 80px);overflow-y: auto"> |
||||||
|
<draggable |
||||||
|
v-model="localState" |
||||||
|
class="row" |
||||||
|
@update="onOrderUpdate" |
||||||
|
> |
||||||
|
<v-col v-for="(item,i) in (isPublicForm ? localFilesState : localState)" :key="i" cols="4"> |
||||||
|
<v-card |
||||||
|
class="modal-thumbnail-card align-center justify-center d-flex" |
||||||
|
height="200px" |
||||||
|
style="position: relative" |
||||||
|
> |
||||||
|
<v-icon |
||||||
|
v-if="_isUIAllowed('tableAttachment') && !isPublicGrid && !isLocked" |
||||||
|
small |
||||||
|
class="remove-icon" |
||||||
|
@click="removeItem(i)" |
||||||
|
> |
||||||
|
mdi-close-circle |
||||||
|
</v-icon> |
||||||
|
<v-icon color="grey" class="download-icon" @click.stop="downloadItem(item,i)"> |
||||||
|
mdi-download |
||||||
|
</v-icon> |
||||||
|
<div class="pa-2 d-flex align-center" style="height:200px"> |
||||||
|
<img |
||||||
|
v-if="isImage(item.title, item.mimetype)" |
||||||
|
style="max-height: 100%;max-width: 100%" |
||||||
|
alt="#" |
||||||
|
:src="item.url || item.data" |
||||||
|
@click="selectImage(item.url,i)" |
||||||
|
> |
||||||
|
|
||||||
|
<v-icon v-else-if="item.icon" size="33" @click="openUrl(item.url || item.data,'_blank')"> |
||||||
|
{{ |
||||||
|
item.icon |
||||||
|
}} |
||||||
|
</v-icon> |
||||||
|
<v-icon v-else size="33" @click="openUrl(item.url || item.data,'_blank')"> |
||||||
|
mdi-file |
||||||
|
</v-icon> |
||||||
|
</div> |
||||||
|
</v-card> |
||||||
|
<p class="caption mt-2 modal-title" :title="item.title"> |
||||||
|
{{ item.title }} |
||||||
|
</p> |
||||||
|
</v-col> |
||||||
|
</draggable> |
||||||
|
</v-container> |
||||||
|
</div> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
|
||||||
|
<v-overlay v-if="showImage" v-model="showImage" z-index="99999" opacity=".93"> |
||||||
|
<div v-click-outside="hideIfVisible" class="image-overlay-container"> |
||||||
|
<template v-if="showImage && selectedImage"> |
||||||
|
<v-carousel v-model="carousel" height="calc(100vh - 100px)" hide-delimiters> |
||||||
|
<v-carousel-item |
||||||
|
v-for="(item,i) in (isPublicForm ? localFilesState : localState)" |
||||||
|
:key="i" |
||||||
|
> |
||||||
|
<div class="mx-auto d-flex flex-column justify-center align-center" style="min-height:100px"> |
||||||
|
<p class="title text-center"> |
||||||
|
{{ item.title }} |
||||||
|
<v-icon class="ml-3" color="grey" @click.stop="downloadItem(item,i)"> |
||||||
|
mdi-download |
||||||
|
</v-icon> |
||||||
|
</p> |
||||||
|
<div style="width:90vh;height:calc(100vh - 150px)" class="d-flex align-center justify-center"> |
||||||
|
<img |
||||||
|
v-if="isImage(item.title, item.mimetype)" |
||||||
|
style="max-width:90vh;max-height:calc(100vh - 100px)" |
||||||
|
:src="item.url || item.data" |
||||||
|
> |
||||||
|
<v-icon v-else-if="item.icon" size="55"> |
||||||
|
{{ item.icon }} |
||||||
|
</v-icon> |
||||||
|
<v-icon v-else size="55"> |
||||||
|
mdi-file |
||||||
|
</v-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-carousel-item> |
||||||
|
</v-carousel> |
||||||
|
</template> |
||||||
|
<v-sheet |
||||||
|
v-if="showImage" |
||||||
|
class="mx-auto align-center justify-center" |
||||||
|
max-width="90vw" |
||||||
|
height="80px" |
||||||
|
style="background: transparent" |
||||||
|
> |
||||||
|
<v-slide-group |
||||||
|
multiple |
||||||
|
show-arrows |
||||||
|
> |
||||||
|
<v-slide-item |
||||||
|
v-for="(item,i) in (isPublicForm ? localFilesState : localState)" |
||||||
|
:key="i" |
||||||
|
> |
||||||
|
<v-card |
||||||
|
:key="i" |
||||||
|
class="ma-2 pa-2 d-flex align-center justify-center overlay-thumbnail" |
||||||
|
:class="{active: carousel === i}" |
||||||
|
width="48" |
||||||
|
height="48" |
||||||
|
@click="carousel = i" |
||||||
|
> |
||||||
|
<img |
||||||
|
v-if="isImage(item.title, item.mimetype)" |
||||||
|
style="max-width:100%;max-height:100%" |
||||||
|
:src="item.url || item.data" |
||||||
|
> |
||||||
|
<v-icon v-else-if="item.icon" size="48"> |
||||||
|
{{ item.icon }} |
||||||
|
</v-icon> |
||||||
|
<v-icon v-else size="48"> |
||||||
|
mdi-file |
||||||
|
</v-icon> |
||||||
|
</v-card> |
||||||
|
</v-slide-item> |
||||||
|
</v-slide-group> |
||||||
|
</v-sheet> |
||||||
|
<v-icon x-large class="close-icon" @click="showImage=false"> |
||||||
|
mdi-close-circle |
||||||
|
</v-icon> |
||||||
|
</div> |
||||||
|
</v-overlay> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import FileSaver from 'file-saver' |
||||||
|
import draggable from 'vuedraggable' |
||||||
|
import { isImage } from '@/components/project/spreadsheet/helpers/imageExt' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'EditableAttachmentCell', |
||||||
|
components: { draggable }, |
||||||
|
props: ['dbAlias', 'value', 'active', 'isLocked', 'meta', 'column', 'isPublicGrid', 'isForm', 'isPublicForm', 'viewId'], |
||||||
|
data: () => ({ |
||||||
|
carousel: null, |
||||||
|
uploading: false, |
||||||
|
localState: '', |
||||||
|
dialog: false, |
||||||
|
showImage: false, |
||||||
|
selectedImage: null, |
||||||
|
dragOver: false, |
||||||
|
localFilesState: [], |
||||||
|
urlString: '' |
||||||
|
}), |
||||||
|
watch: { |
||||||
|
value(val, prev) { |
||||||
|
try { |
||||||
|
this.localState = ((typeof val === 'string' && val !== prev ? JSON.parse(val) : val) || []).filter(Boolean) |
||||||
|
} catch (e) { |
||||||
|
this.localState = [] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
try { |
||||||
|
this.localState = ((typeof this.value === 'string' ? JSON.parse(this.value) : this.value) || []).filter(Boolean) |
||||||
|
} catch (e) { |
||||||
|
this.localState = [] |
||||||
|
} |
||||||
|
document.addEventListener('keydown', this.onArrowDown) |
||||||
|
}, |
||||||
|
beforeDestroy() { |
||||||
|
document.removeEventListener('keydown', this.onArrowDown) |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
async uploadByUrl() { |
||||||
|
const data = await this.$api.storage.uploadByUrl( |
||||||
|
{ |
||||||
|
path: ['noco', this.projectName, this.meta.title, this.column.title].join('/') |
||||||
|
}, |
||||||
|
[{ |
||||||
|
url: this.urlString |
||||||
|
}] |
||||||
|
) |
||||||
|
|
||||||
|
this.localState.push(...data) |
||||||
|
}, |
||||||
|
openUrl(url, target) { |
||||||
|
window.open(url, target) |
||||||
|
}, |
||||||
|
isImage, |
||||||
|
hideIfVisible() { |
||||||
|
if (this.showImage) { |
||||||
|
this.showImage = false |
||||||
|
} |
||||||
|
}, |
||||||
|
selectImage(selectedImage, i) { |
||||||
|
this.carousel = i |
||||||
|
this.selectedImage = selectedImage |
||||||
|
this.showImage = true |
||||||
|
}, |
||||||
|
addFile() { |
||||||
|
if (!this.isLocked) { |
||||||
|
this.$refs.file.click() |
||||||
|
} |
||||||
|
}, |
||||||
|
async onFileSelection() { |
||||||
|
if (this.isPublicGrid) { |
||||||
|
return |
||||||
|
} |
||||||
|
if (!this.$refs.file.files || !this.$refs.file.files.length) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (this.isPublicForm) { |
||||||
|
this.localFilesState.push(...Array.from(this.$refs.file.files).map((file) => { |
||||||
|
const res = { file, title: file.name } |
||||||
|
if (isImage(file.name, file.mimetype)) { |
||||||
|
const reader = new FileReader() |
||||||
|
reader.onload = (e) => { |
||||||
|
this.$set(res, 'data', e.target.result) |
||||||
|
} |
||||||
|
reader.readAsDataURL(file) |
||||||
|
} |
||||||
|
return res |
||||||
|
})) |
||||||
|
|
||||||
|
this.$emit('input', this.localFilesState.map(f => f.file)) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
this.uploading = true |
||||||
|
for (const file of this.$refs.file.files) { |
||||||
|
try { |
||||||
|
const data = await this.$api.storage.upload( |
||||||
|
{ |
||||||
|
path: ['noco', this.projectName, this.meta.title, this.column.title].join('/') |
||||||
|
}, { |
||||||
|
files: file, |
||||||
|
json: '{}' |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
this.localState.push(...data) |
||||||
|
} catch (e) { |
||||||
|
this.$toast.error((e.message) || 'Some internal error occurred').goAway(3000) |
||||||
|
this.uploading = false |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
this.uploading = false |
||||||
|
this.$emit('input', JSON.stringify(this.localState)) |
||||||
|
this.$emit('update') |
||||||
|
}, |
||||||
|
onOrderUpdate() { |
||||||
|
this.$emit('input', JSON.stringify(this.localState)) |
||||||
|
this.$emit('update') |
||||||
|
}, |
||||||
|
removeItem(i) { |
||||||
|
if (this.isPublicForm) { |
||||||
|
this.localFilesState.splice(i, 1) |
||||||
|
this.$emit('input', this.localFilesState.map(f => f.file)) |
||||||
|
} else { |
||||||
|
this.localState.splice(i, 1) |
||||||
|
this.$emit('input', JSON.stringify(this.localState)) |
||||||
|
} |
||||||
|
this.$emit('update') |
||||||
|
}, |
||||||
|
downloadItem(item) { |
||||||
|
FileSaver.saveAs(item.url || item.data, item.title) |
||||||
|
}, |
||||||
|
onArrowDown(e) { |
||||||
|
if (!this.showImage) { |
||||||
|
return |
||||||
|
} |
||||||
|
e = e || window.event |
||||||
|
// eslint-disable-next-line eqeqeq |
||||||
|
if (e.keyCode == '37') { |
||||||
|
this.carousel = (this.carousel || this.localState.length) - 1 |
||||||
|
// eslint-disable-next-line eqeqeq |
||||||
|
} else if (e.keyCode == '39') { |
||||||
|
this.carousel = ++this.carousel % this.localState.length |
||||||
|
// eslint-disable-next-line eqeqeq |
||||||
|
} else if (e.keyCode == '27') { |
||||||
|
this.hideIfVisible() |
||||||
|
} |
||||||
|
}, |
||||||
|
async onFileDrop(e) { |
||||||
|
this.dragOver = false |
||||||
|
this.$refs.file.files = e.dataTransfer.files |
||||||
|
await this.onFileSelection() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.img-container { |
||||||
|
margin: 0 -2px; |
||||||
|
} |
||||||
|
|
||||||
|
.no-overflow { |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.add { |
||||||
|
transition: .2s background-color; |
||||||
|
/*background-color: #666666ee;*/ |
||||||
|
border-radius: 4px; |
||||||
|
height: 33px; |
||||||
|
margin: 5px 2px; |
||||||
|
} |
||||||
|
|
||||||
|
.add:hover { |
||||||
|
/*background-color: #66666699;*/ |
||||||
|
} |
||||||
|
|
||||||
|
.thumbnail { |
||||||
|
height: 99px; |
||||||
|
width: 99px; |
||||||
|
margin: 2px; |
||||||
|
border-radius: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
.thumbnail img { |
||||||
|
/*max-height: 33px;*/ |
||||||
|
max-width: 99px; |
||||||
|
} |
||||||
|
|
||||||
|
.main { |
||||||
|
min-height: 20px; |
||||||
|
position: relative; |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.expand-icon { |
||||||
|
margin-left: 8px; |
||||||
|
border-radius: 2px; |
||||||
|
/*opacity: 0;*/ |
||||||
|
transition: .3s background-color; |
||||||
|
} |
||||||
|
|
||||||
|
.expand-icon:hover { |
||||||
|
/*opacity: 1;*/ |
||||||
|
background-color: var(--v-primary-lighten4); |
||||||
|
} |
||||||
|
|
||||||
|
.modal-thumbnail img { |
||||||
|
height: 50px; |
||||||
|
max-width: 100%; |
||||||
|
border-radius: 4px; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
.modal-thumbnail { |
||||||
|
position: relative; |
||||||
|
margin: 10px 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.remove-icon { |
||||||
|
position: absolute; |
||||||
|
top: 5px; |
||||||
|
right: 5px |
||||||
|
} |
||||||
|
|
||||||
|
.modal-thumbnail-card { |
||||||
|
|
||||||
|
.download-icon { |
||||||
|
position: absolute; |
||||||
|
bottom: 5px; |
||||||
|
right: 5px; |
||||||
|
opacity: 0; |
||||||
|
transition: .4s opacity; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover .download-icon { |
||||||
|
opacity: 1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.image-overlay-container { |
||||||
|
max-height: 100vh; |
||||||
|
overflow-y: auto; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.image-overlay-container .close-icon { |
||||||
|
position: fixed; |
||||||
|
top: 15px; |
||||||
|
right: 15px |
||||||
|
} |
||||||
|
|
||||||
|
.overlay-thumbnail { |
||||||
|
transition: .4s transform, .4s opacity; |
||||||
|
opacity: .5; |
||||||
|
} |
||||||
|
|
||||||
|
.overlay-thumbnail.active { |
||||||
|
transform: scale(1.4); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.overlay-thumbnail:hover { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.modal-title { |
||||||
|
text-overflow: ellipsis; |
||||||
|
white-space: nowrap; |
||||||
|
width: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.modal-thumbnail-card { |
||||||
|
transition: .4s transform; |
||||||
|
} |
||||||
|
|
||||||
|
.modal-thumbnail-card:hover { |
||||||
|
transform: scale(1.05); |
||||||
|
} |
||||||
|
|
||||||
|
.drop-overlay { |
||||||
|
z-index: 5; |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 5px; |
||||||
|
background: #aaaaaa44; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
pointer-events: none; |
||||||
|
} |
||||||
|
|
||||||
|
.expand-icon { |
||||||
|
opacity: 0; |
||||||
|
transition: .4s opacity; |
||||||
|
} |
||||||
|
|
||||||
|
.main:hover .expand-icon { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* @author Wing-Kam Wong <wingkwong.code@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,80 @@ |
|||||||
|
<template> |
||||||
|
<input v-model="localState" v-on="parentListeners"> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { isValidURL } from '@/helpers' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'EditableUrlCell', |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
column: Object |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
if (!( |
||||||
|
this.column && |
||||||
|
this.column.meta && |
||||||
|
this.column.meta.validate |
||||||
|
) || isValidURL(val)) { this.$emit('input', val) } |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
if (this.$listeners.cancel) { |
||||||
|
$listeners.cancel = this.$listeners.cancel |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input, textarea { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,132 @@ |
|||||||
|
<template> |
||||||
|
<v-select |
||||||
|
v-model="localState" |
||||||
|
solo |
||||||
|
dense |
||||||
|
flat |
||||||
|
:items="enumValues" |
||||||
|
hide-details |
||||||
|
class="mt-0" |
||||||
|
:clearable="!column.rqd" |
||||||
|
v-on="parentListeners" |
||||||
|
> |
||||||
|
<template #selection="{item}"> |
||||||
|
<div |
||||||
|
class="d-100" |
||||||
|
:class="{ |
||||||
|
'text-center' : !isForm |
||||||
|
}" |
||||||
|
> |
||||||
|
<v-chip small :color="colors[enumValues.indexOf(item) % colors.length]" class="ma-1"> |
||||||
|
{{ item }} |
||||||
|
</v-chip> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template #item="{item}"> |
||||||
|
<v-chip small :color="colors[enumValues.indexOf(item) % colors.length]"> |
||||||
|
{{ item }} |
||||||
|
</v-chip> |
||||||
|
</template> |
||||||
|
<template #append> |
||||||
|
<v-icon small class="mt-1"> |
||||||
|
mdi-menu-down |
||||||
|
</v-icon> |
||||||
|
</template> |
||||||
|
</v-select> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import colors from '@/mixins/colors' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'EnumListEditableCell', |
||||||
|
mixins: [colors], |
||||||
|
|
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
column: Object, |
||||||
|
isForm: Boolean |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value && this.value.replace(/\\'/g, '\'').replace(/^'|'$/g, '') |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
enumValues() { |
||||||
|
if (this.column && this.column.dtxp) { |
||||||
|
return this.column.dtxp |
||||||
|
.split(',') |
||||||
|
.map(v => v.replace(/\\'/g, '\'').replace(/^'|'$/g, '')) |
||||||
|
} |
||||||
|
return [] |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// this.$el.focus(); |
||||||
|
// let event; |
||||||
|
// event = document.createEvent('MouseEvents'); |
||||||
|
// event.initMouseEvent('mousedown', true, true, window); |
||||||
|
// this.$el.dispatchEvent(event); |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
::v-deep { |
||||||
|
.v-select { |
||||||
|
min-width: 150px; |
||||||
|
} |
||||||
|
.v-input__slot{ |
||||||
|
padding-right: 0 !important; |
||||||
|
padding-left: 35px !important; |
||||||
|
} |
||||||
|
.v-input__icon.v-input__icon--clear { |
||||||
|
width: 15px !important; |
||||||
|
min-width: 13px !important; |
||||||
|
|
||||||
|
.v-icon { |
||||||
|
font-size: 13px !important; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,101 @@ |
|||||||
|
<template> |
||||||
|
<div class="d-flex align-center"> |
||||||
|
<div> |
||||||
|
<div v-for="(val,i) of enumValues" :key="val" class="item"> |
||||||
|
<input :id="`key-radio-${val}`" v-model="localState" type="radio" class="orange--text" :value="val"> |
||||||
|
<label |
||||||
|
class="py-1 px-3 d-inline-block my-1 label" |
||||||
|
:for="`key-radio-${val}`" |
||||||
|
:style="{ |
||||||
|
background:colors[i % colors.length ] |
||||||
|
}" |
||||||
|
>{{ val }}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { enumColor as colors } from '@/components/project/spreadsheet/helpers/colors' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'EnumRadioEditableCell', |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
column: Object |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
colors() { |
||||||
|
return this.$store.state.settings.darkTheme ? colors.dark : colors.light |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
this.$emit('update') |
||||||
|
} |
||||||
|
}, |
||||||
|
enumValues() { |
||||||
|
if (this.column && this.column.dtxp) { |
||||||
|
return this.column.dtxp.split(',').map(v => v.replace(/^'|'$/g, '')) |
||||||
|
} |
||||||
|
return [] |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// this.$el.focus(); |
||||||
|
// let event; |
||||||
|
// event = document.createEvent('MouseEvents'); |
||||||
|
// event.initMouseEvent('mousedown', true, true, window); |
||||||
|
// this.$el.dispatchEvent(event); |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
.label { |
||||||
|
border-radius: 25px; |
||||||
|
} |
||||||
|
|
||||||
|
.item { |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,69 @@ |
|||||||
|
<template> |
||||||
|
<input v-model="localState" type="number" v-on="parentListeners"> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'FloatCell', |
||||||
|
props: { |
||||||
|
value: [String, Number] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', +val) |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,69 @@ |
|||||||
|
<template> |
||||||
|
<input v-model="localState" type="number" v-on="parentListeners"> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'IntegerCell', |
||||||
|
props: { |
||||||
|
value: [String, Number] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', parseInt(val, 10)) |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,138 @@ |
|||||||
|
<template> |
||||||
|
<v-dialog :is="expand ? 'v-dialog' : 'div'" v-model="expand" max-width="800px" class="cell-container" @keydown.stop.enter> |
||||||
|
<div class="d-flex pa-1 " :class="{backgroundColor:expand}"> |
||||||
|
<v-spacer /> |
||||||
|
<v-icon small class="mr-2" @click="expand = !expand"> |
||||||
|
{{ expand ? 'mdi-arrow-collapse' : 'mdi-arrow-expand' }} |
||||||
|
</v-icon> |
||||||
|
<template v-if="!isForm"> |
||||||
|
<v-btn outlined x-small class="mr-1" @click="$emit('cancel')"> |
||||||
|
<!-- Cancel --> |
||||||
|
{{ $t('general.cancel') }} |
||||||
|
</v-btn> |
||||||
|
<v-btn x-small color="primary" :disabled="!isValid" @click="save"> |
||||||
|
<!-- Save --> |
||||||
|
{{ $t('general.save') }} |
||||||
|
</v-btn> |
||||||
|
</template> |
||||||
|
<v-btn v-else-if="expand" x-small @click="expand=false"> |
||||||
|
<!-- Close --> |
||||||
|
{{ $t('general.close') }} |
||||||
|
</v-btn> |
||||||
|
</div> |
||||||
|
<monaco-json-object-editor |
||||||
|
v-if="expand" |
||||||
|
v-model="localState" |
||||||
|
class="text-left caption" |
||||||
|
style="width: 300px;min-height:min(600px,80vh);min-width:100%; " |
||||||
|
@validate="validate" |
||||||
|
/> |
||||||
|
<monaco-json-object-editor |
||||||
|
v-else |
||||||
|
v-model="localState" |
||||||
|
class="text-left caption" |
||||||
|
style="width: 300px;min-height:200px;min-width:100%;" |
||||||
|
@validate="validate" |
||||||
|
/> |
||||||
|
<div v-show="error" class="px-2 py-1 text-left caption error--text"> |
||||||
|
{{ error }} |
||||||
|
</div> |
||||||
|
</v-dialog> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import MonacoJsonObjectEditor from '@/components/monaco/MonacoJsonObjectEditor' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'JsonEditableCell', |
||||||
|
components: { MonacoJsonObjectEditor }, |
||||||
|
props: { |
||||||
|
value: [String, Object], |
||||||
|
isForm: Boolean |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
localState: '', |
||||||
|
expand: false, |
||||||
|
isValid: true, |
||||||
|
error: undefined |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
|
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
value(val) { |
||||||
|
try { |
||||||
|
this.localState = typeof val === 'string' ? JSON.parse(val) : val |
||||||
|
} catch (e) { |
||||||
|
// ignore parse error for invalid JSON |
||||||
|
} |
||||||
|
}, |
||||||
|
localState(val) { |
||||||
|
if (this.isForm) { |
||||||
|
this.$emit('input', JSON.stringify(val)) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
try { |
||||||
|
this.localState = typeof this.value === 'string' ? JSON.parse(this.value) : this.value |
||||||
|
} catch (e) { |
||||||
|
// ignore parse error for invalid JSON |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
save() { |
||||||
|
this.expand = false |
||||||
|
this.$emit('input', JSON.stringify(this.localState)) |
||||||
|
}, |
||||||
|
validate(n, e) { |
||||||
|
this.isValid = n |
||||||
|
this.error = e |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.cell-container { |
||||||
|
width: 100% |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,71 @@ |
|||||||
|
<template> |
||||||
|
<div class="d-100 h-100" :class="{'nc-cell-hover-show': localState == 0 || !localState}"> |
||||||
|
<v-rating |
||||||
|
v-model="localState" |
||||||
|
:length="ratingMeta.max" |
||||||
|
dense |
||||||
|
x-small |
||||||
|
:readonly="readOnly" |
||||||
|
clearable |
||||||
|
> |
||||||
|
<template #item="{isFilled, click}"> |
||||||
|
<v-icon v-if="isFilled" :size="15" :color="ratingMeta.color" @click="click"> |
||||||
|
{{ fullIcon }} |
||||||
|
</v-icon> |
||||||
|
<v-icon |
||||||
|
v-else |
||||||
|
:color="ratingMeta.color" |
||||||
|
:size="15" |
||||||
|
class="nc-cell-hover-show" |
||||||
|
@click="click" |
||||||
|
> |
||||||
|
{{ emptyIcon }} |
||||||
|
</v-icon> |
||||||
|
</template> |
||||||
|
</v-rating> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'RatingCell', |
||||||
|
props: { |
||||||
|
column: Object, |
||||||
|
value: [String, Number], |
||||||
|
readOnly: Boolean |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
fullIcon() { |
||||||
|
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.full) || 'mdi-star' |
||||||
|
}, |
||||||
|
emptyIcon() { |
||||||
|
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.empty) || 'mdi-star-outline' |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
ratingMeta() { |
||||||
|
return { |
||||||
|
icon: { |
||||||
|
full: 'mdi-star', |
||||||
|
empty: 'mdi-star-outline' |
||||||
|
}, |
||||||
|
color: '#fcb401', |
||||||
|
max: 5, |
||||||
|
...(this.column && this.column.meta |
||||||
|
? this.column.meta |
||||||
|
: {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,101 @@ |
|||||||
|
<template> |
||||||
|
<div class="d-flex align-center"> |
||||||
|
<div> |
||||||
|
<div v-for="(val,i) of setValues" :key="val" class=""> |
||||||
|
<input :id="`key-check-box-${val}`" v-model="localState" type="checkbox" class="orange--text" :value="val"> |
||||||
|
<label |
||||||
|
class="py-1 px-3 d-inline-block my-1 label" |
||||||
|
:for="`key-check-box-${val}`" |
||||||
|
:style="{ |
||||||
|
background:colors[i % colors.length ] |
||||||
|
}" |
||||||
|
>{{ val }}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import colors from '@/components/project/spreadsheet/helpers/colors' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'SetListCheckboxCell', |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
column: Object, |
||||||
|
values: Array |
||||||
|
}, |
||||||
|
data() { |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
colors() { |
||||||
|
return this.$store.state.settings.darkTheme ? colors.dark : colors.light |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return (this.value && this.value.split(',')) || [] |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val.join(',')) |
||||||
|
this.$emit('update') |
||||||
|
} |
||||||
|
}, |
||||||
|
setValues() { |
||||||
|
if (this.column && this.column.dtxp) { |
||||||
|
return this.column.dtxp.split(',').map(v => v.replace(/^'|'$/g, '')) |
||||||
|
} |
||||||
|
return this.values || [] |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$el.focus() |
||||||
|
const event = document.createEvent('MouseEvents') |
||||||
|
event.initMouseEvent('mousedown', true, true, window) |
||||||
|
this.$el.dispatchEvent(event) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
.label { |
||||||
|
border-radius: 25px; |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,129 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<v-combobox |
||||||
|
v-model="localState" |
||||||
|
:items="setValues" |
||||||
|
multiple |
||||||
|
chips |
||||||
|
flat |
||||||
|
dense |
||||||
|
solo |
||||||
|
hide-details |
||||||
|
deletable-chips |
||||||
|
class="text-center mt-0 " |
||||||
|
> |
||||||
|
<template #selection="data"> |
||||||
|
<v-chip |
||||||
|
:key="data.item" |
||||||
|
small |
||||||
|
class="ma-1 " |
||||||
|
:color="colors[setValues.indexOf(data.item) % colors.length]" |
||||||
|
@click:close="data.parent.selectItem(data.item)" |
||||||
|
> |
||||||
|
{{ data.item }} |
||||||
|
</v-chip> |
||||||
|
</template> |
||||||
|
|
||||||
|
<template #item="{item}"> |
||||||
|
<v-chip small :color="colors[setValues.indexOf(item) % colors.length]"> |
||||||
|
{{ item }} |
||||||
|
</v-chip> |
||||||
|
</template> |
||||||
|
<template #append> |
||||||
|
<v-icon small class="mt-2"> |
||||||
|
mdi-menu-down |
||||||
|
</v-icon> |
||||||
|
</template> |
||||||
|
</v-combobox> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import colors from '@/mixins/colors' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'SetListEditableCell', |
||||||
|
mixins: [colors], |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
column: Object |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value && this.value |
||||||
|
.match(/(?:[^',]|\\')+(?='?(?:,|$))/g) |
||||||
|
.map(v => v.replace(/\\'/g, '\'')) |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val.filter(v => this.setValues.includes(v)).join(',')) |
||||||
|
} |
||||||
|
}, |
||||||
|
setValues() { |
||||||
|
if (this.column && this.column.dtxp) { |
||||||
|
return this.column.dtxp |
||||||
|
.match(/(?:[^']|\\')+(?='?(?:,|$))/g) |
||||||
|
.map(v => v.replace(/\\'/g, '\'').replace(/^'|'$/g, '')) |
||||||
|
} |
||||||
|
return [] |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// this.$el.focus(); |
||||||
|
// let event; |
||||||
|
// event = document.createEvent('MouseEvents'); |
||||||
|
// event.initMouseEvent('mousedown', true, true, window); |
||||||
|
// this.$el.dispatchEvent(event); |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
select { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
-webkit-appearance: menulist; |
||||||
|
/*webkit browsers */ |
||||||
|
-moz-appearance: menulist; |
||||||
|
/*Firefox */ |
||||||
|
appearance: menulist; |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,81 @@ |
|||||||
|
<template> |
||||||
|
<textarea |
||||||
|
ref="textarea" |
||||||
|
v-model="localState" |
||||||
|
rows="4" |
||||||
|
v-on="parentListeners" |
||||||
|
@keydown.alt.enter.stop |
||||||
|
@keydown.shift.enter.stop |
||||||
|
/> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'TextAreaCell', |
||||||
|
props: { |
||||||
|
value: String |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
|
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
this.localState = this.value |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$refs.textarea && this.$refs.textarea.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input, textarea { |
||||||
|
width: 100%; |
||||||
|
min-height: 60px; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,105 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<div v-if="!isForm" class="d-flex ma-1"> |
||||||
|
<v-spacer /> |
||||||
|
<v-btn v-if="!isForm" outlined x-small class="mr-1" @click="$emit('cancel')"> |
||||||
|
<!-- Cancel --> |
||||||
|
{{ $t('general.cancel') }} |
||||||
|
</v-btn> |
||||||
|
<v-btn v-if="!isForm" x-small color="primary" @click="save"> |
||||||
|
<!-- Save --> |
||||||
|
{{ $t('general.save') }} |
||||||
|
</v-btn> |
||||||
|
</div> |
||||||
|
<textarea |
||||||
|
ref="textarea" |
||||||
|
v-model="localState" |
||||||
|
rows="3" |
||||||
|
v-on="parentListeners" |
||||||
|
@input="isForm && save()" |
||||||
|
@keydown.stop.enter |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'TextAreaCell', |
||||||
|
props: { |
||||||
|
value: String, |
||||||
|
isForm: Boolean |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
localState: '' |
||||||
|
}), |
||||||
|
computed: { |
||||||
|
|
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
value(val) { |
||||||
|
this.localState = val |
||||||
|
}, |
||||||
|
localState(val) { |
||||||
|
if (this.isForm) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
this.localState = this.value |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$refs.textarea && this.$refs.textarea.focus() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
save() { |
||||||
|
this.$emit('input', this.localState) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input, textarea { |
||||||
|
width: 100%; |
||||||
|
min-height:60px; |
||||||
|
height: calc(100% - 28px); |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,73 @@ |
|||||||
|
<template> |
||||||
|
<input v-model="localState" v-on="parentListeners"> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'TextCell', |
||||||
|
props: { |
||||||
|
value: [String, Object, Number, Boolean, Array] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
return this.value |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
this.$emit('input', val) |
||||||
|
} |
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
if (this.$listeners.cancel) { |
||||||
|
$listeners.cancel = this.$listeners.cancel |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
this.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
input, textarea { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,111 @@ |
|||||||
|
<template> |
||||||
|
<v-menu> |
||||||
|
<template #activator="{on}"> |
||||||
|
<input v-model="localState" class="value" v-on="on"> |
||||||
|
</template> |
||||||
|
<div class="d-flex flex-column justify-center" @click.stop> |
||||||
|
<v-time-picker v-model="localState" v-on="parentListeners" /> |
||||||
|
<v-btn small color="primary" @click="$emit('save')"> |
||||||
|
<!-- Save --> |
||||||
|
{{ $t('general.save') }} |
||||||
|
</v-btn> |
||||||
|
</div> |
||||||
|
</v-menu> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import dayjs from 'dayjs' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'TimePickerCell', |
||||||
|
props: { |
||||||
|
value: [String, Date] |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
isMysql() { |
||||||
|
return ['mysql', 'mysql2'].indexOf(this.$store.getters['project/GtrClientType']) |
||||||
|
}, |
||||||
|
localState: { |
||||||
|
get() { |
||||||
|
if (!this.value) { |
||||||
|
return this.value |
||||||
|
} |
||||||
|
let dateTime = dayjs(this.value) |
||||||
|
if (!dateTime.isValid()) { |
||||||
|
dateTime = dayjs(this.value, 'HH:mm:ss') |
||||||
|
} |
||||||
|
if (!dateTime.isValid()) { |
||||||
|
dateTime = dayjs(`1999-01-01 ${this.value}`) |
||||||
|
} |
||||||
|
if (!dateTime.isValid()) { |
||||||
|
return this.value |
||||||
|
} |
||||||
|
return dateTime.format('HH:mm:ss') |
||||||
|
}, |
||||||
|
set(val) { |
||||||
|
const dateTime = dayjs(`1999-01-01 ${val}:00`) |
||||||
|
if (dateTime.isValid()) { |
||||||
|
if (this.isMysql) { |
||||||
|
this.$emit('input', dateTime.format('YYYY-MM-DD HH:mm:ss')) |
||||||
|
} else { |
||||||
|
this.$emit('input', dateTime.format('YYYY-MM-DD HH:mm:ssZ')) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
parentListeners() { |
||||||
|
const $listeners = {} |
||||||
|
|
||||||
|
if (this.$listeners.blur) { |
||||||
|
$listeners.blur = this.$listeners.blur |
||||||
|
} |
||||||
|
if (this.$listeners.focus) { |
||||||
|
$listeners.focus = this.$listeners.focus |
||||||
|
} |
||||||
|
|
||||||
|
if (this.$listeners.cancel) { |
||||||
|
$listeners.cancel = this.$listeners.cancel |
||||||
|
} |
||||||
|
|
||||||
|
return $listeners |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
if (this.$el && this.$el.$el) { |
||||||
|
this.$el.$el.focus() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.value { |
||||||
|
width: 100%; |
||||||
|
min-height: 20px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<!-- |
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||||
|
* |
||||||
|
* @author Naveen MR <oof1lab@gmail.com> |
||||||
|
* @author Pranav C Balan <pranavxc@gmail.com> |
||||||
|
* |
||||||
|
* @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/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
--> |
@ -0,0 +1,48 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import type { ColumnType } from 'nocodb-sdk' |
||||||
|
import { useColumn } from '~/composables/column' |
||||||
|
|
||||||
|
const { column, value } = defineProps<{ column: ColumnType; value: any }>() |
||||||
|
provide('column', column) |
||||||
|
provide('value', value) |
||||||
|
|
||||||
|
const { |
||||||
|
isSet, |
||||||
|
isEnum, |
||||||
|
isURL, |
||||||
|
isEmail, |
||||||
|
isJSON, |
||||||
|
isDate, |
||||||
|
isDateTime, |
||||||
|
isTime, |
||||||
|
isBoolean, |
||||||
|
isDuration, |
||||||
|
isRating, |
||||||
|
isCurrency, |
||||||
|
isAttachment, |
||||||
|
isTextArea, |
||||||
|
} = useColumn(column) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<!-- <CellEditableAttachment v-if="isAttachment" /> --> |
||||||
|
<CellSetList v-if="isSet" /> |
||||||
|
<CellEnum v-else-if="isEnum" /> |
||||||
|
<!-- <CellUrl v-else-if="isURL" /> --> |
||||||
|
<!-- <CellEmail v-else-if="isEmail" /> --> |
||||||
|
<!-- <CellJson v-else-if="isJSON" /> --> |
||||||
|
<!-- <CellDate v-else-if="isDate" /> --> |
||||||
|
<!-- <CellDateTime v-else-if="isDateTime" /> --> |
||||||
|
<!-- <CellTime v-else-if="isTime" /> --> |
||||||
|
<CellBoolean v-else-if="isBoolean" /> |
||||||
|
<!-- <CellDuration v-else-if="isDuration" /> --> |
||||||
|
<!-- <CellRating v-else-if="isRating" /> --> |
||||||
|
<!-- <CellCurrency v-else-if="isCurrency" /> --> |
||||||
|
<span |
||||||
|
v-else |
||||||
|
:title="title" |
||||||
|
>{{ value }}</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
</style> |
@ -0,0 +1,189 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import type { ColumnType } from 'nocodb-sdk' |
||||||
|
import { useColumn } from '~/composables/column' |
||||||
|
|
||||||
|
const { column, value } = defineProps<{ column: ColumnType; value: any }>() |
||||||
|
provide('column', column) |
||||||
|
provide('value', value) |
||||||
|
|
||||||
|
const { |
||||||
|
isSet, |
||||||
|
isEnum, |
||||||
|
isURL, |
||||||
|
isEmail, |
||||||
|
isJSON, |
||||||
|
isDate, |
||||||
|
isDateTime, |
||||||
|
isTime, |
||||||
|
isBoolean, |
||||||
|
isDuration, |
||||||
|
isRating, |
||||||
|
isCurrency, |
||||||
|
isAttachment, |
||||||
|
isTextArea, |
||||||
|
} = useColumn(column) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div |
||||||
|
class="nc-cell" |
||||||
|
@keydown.stop.left |
||||||
|
@keydown.stop.right |
||||||
|
@keydown.stop.up |
||||||
|
@keydown.stop.down |
||||||
|
> |
||||||
|
<EditableAttachmentCell |
||||||
|
v-if="isAttachment" |
||||||
|
v-model="localState" |
||||||
|
:active="active" |
||||||
|
:db-alias="dbAlias" |
||||||
|
:meta="meta" |
||||||
|
:is-form="isForm" |
||||||
|
:column="column" |
||||||
|
:is-public-grid="isPublic && !isForm" |
||||||
|
:is-public-form="isPublic && isForm" |
||||||
|
:view-id="viewId" |
||||||
|
:is-locked="isLocked" |
||||||
|
v-on="$listeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<RatingCell |
||||||
|
v-else-if="isRating" |
||||||
|
v-model="localState" |
||||||
|
:active="active" |
||||||
|
:is-form="isForm" |
||||||
|
:column="column" |
||||||
|
:is-public-grid="isPublic && !isForm" |
||||||
|
:is-public-form="isPublic && isForm" |
||||||
|
:is-locked="isLocked" |
||||||
|
v-on="$listeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<DurationCell |
||||||
|
v-else-if="isDuration" |
||||||
|
v-model="localState" |
||||||
|
:active="active" |
||||||
|
:is-form="isForm" |
||||||
|
:column="column" |
||||||
|
:is-locked="isLocked" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<BooleanCell |
||||||
|
v-else-if="isBoolean" |
||||||
|
v-model="localState" |
||||||
|
:column="column" |
||||||
|
:is-form="isForm" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<IntegerCell |
||||||
|
v-else-if="isInt" |
||||||
|
v-model="localState" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<FloatCell |
||||||
|
v-else-if="isFloat" |
||||||
|
v-model="localState" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<DatePickerCell |
||||||
|
v-else-if="isDate" |
||||||
|
v-model="localState" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<TimePickerCell |
||||||
|
v-else-if="isTime" |
||||||
|
v-model="localState" |
||||||
|
v-on="parentListeners" |
||||||
|
@save="$emit('save')" |
||||||
|
/> |
||||||
|
|
||||||
|
<DateTimePickerCell |
||||||
|
v-else-if="isDateTime" |
||||||
|
v-model="localState" |
||||||
|
ignore-focus |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<EnumCell |
||||||
|
v-else-if="isEnum && ((!isForm && !active) || isLocked || (isPublic && !isForm))" |
||||||
|
v-model="localState" |
||||||
|
:column="column" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
<EnumListCell |
||||||
|
v-else-if="isEnum" |
||||||
|
v-model="localState" |
||||||
|
:is-form="isForm" |
||||||
|
:column="column" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<JsonEditableCell |
||||||
|
v-else-if="isJSON" |
||||||
|
v-model="localState" |
||||||
|
:is-form="isForm" |
||||||
|
v-on="parentListeners" |
||||||
|
@input="$emit('save')" |
||||||
|
/> |
||||||
|
|
||||||
|
<SetListEditableCell |
||||||
|
v-else-if="isSet && (active || isForm) && !isLocked && !(isPublic && !isForm)" |
||||||
|
v-model="localState" |
||||||
|
:column="column" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
<SetListCell |
||||||
|
v-else-if="isSet" |
||||||
|
v-model="localState" |
||||||
|
:column="column" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<EditableUrlCell v-else-if="isURL" v-model="localState" v-on="parentListeners" /> |
||||||
|
|
||||||
|
<TextCell v-else-if="isString" v-model="localState" v-on="parentListeners" /> |
||||||
|
|
||||||
|
<TextAreaCell |
||||||
|
v-else-if="isTextArea" |
||||||
|
v-model="localState" |
||||||
|
:is-form="isForm" |
||||||
|
v-on="parentListeners" |
||||||
|
/> |
||||||
|
|
||||||
|
<TextCell v-else v-model="localState" v-on="$listeners" /> |
||||||
|
<span v-if="hint" class="nc-hint">{{ hint }}</span> |
||||||
|
|
||||||
|
<div v-if="(isLocked || (isPublic && !isForm)) && !isAttachment" class="nc-locked-overlay" /> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
div { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: var(--v-textColor-base); |
||||||
|
} |
||||||
|
|
||||||
|
.nc-hint { |
||||||
|
font-size: .61rem; |
||||||
|
color: grey; |
||||||
|
} |
||||||
|
|
||||||
|
.nc-cell { |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.nc-locked-overlay { |
||||||
|
position: absolute; |
||||||
|
z-index: 2; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,58 @@ |
|||||||
|
export default { |
||||||
|
light: [ |
||||||
|
|
||||||
|
'#ffdce5', |
||||||
|
'#fee2d5', |
||||||
|
'#ffeab6', |
||||||
|
'#d1f7c4', |
||||||
|
'#ede2fe', |
||||||
|
'#eee', |
||||||
|
'#cfdffe', |
||||||
|
'#d0f1fd', |
||||||
|
'#c2f5e8', |
||||||
|
'#ffdaf6', |
||||||
|
], |
||||||
|
dark: [ |
||||||
|
'#f82b6099', |
||||||
|
'#ff6f2c99', |
||||||
|
'#fcb40099', |
||||||
|
'#20c93399', |
||||||
|
'#8b46ff99', |
||||||
|
'#666', |
||||||
|
'#2d7ff999', |
||||||
|
'#18bfff99', |
||||||
|
'#20d9d299', |
||||||
|
'#ff08c299', |
||||||
|
], |
||||||
|
} |
||||||
|
|
||||||
|
const enumColor = { |
||||||
|
light: [ |
||||||
|
'#cfdffe', |
||||||
|
'#d0f1fd', |
||||||
|
'#c2f5e8', |
||||||
|
'#ffdaf6', |
||||||
|
'#ffdce5', |
||||||
|
'#fee2d5', |
||||||
|
'#ffeab6', |
||||||
|
'#d1f7c4', |
||||||
|
'#ede2fe', |
||||||
|
'#eeeeee', |
||||||
|
], |
||||||
|
dark: [ |
||||||
|
'#2d7ff999', |
||||||
|
'#18bfff99', |
||||||
|
'#20d9d299', |
||||||
|
'#ff08c299', |
||||||
|
'#f82b6099', |
||||||
|
'#ff6f2c99', |
||||||
|
'#fcb40099', |
||||||
|
'#20c93399', |
||||||
|
'#8b46ff99', |
||||||
|
'#666', |
||||||
|
], |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
enumColor, |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
import { SqlUiFactory, UITypes, isVirtualCol } from 'nocodb-sdk' |
||||||
|
import { useProject } from '~/composables/project' |
||||||
|
|
||||||
|
export const useColumn = (column) => { |
||||||
|
const { project } = useProject() |
||||||
|
|
||||||
|
const uiDatatype = column && column.uidt |
||||||
|
const abstractType = isVirtualCol(column) ? null : SqlUiFactory.create(project.value?.bases?.[0]?.config || { client: 'mysql2' }).getAbstractType(column) |
||||||
|
|
||||||
|
const dataTypeLow = column && column.dt && column.dt.toLowerCase() |
||||||
|
const isBoolean = abstractType === 'boolean' |
||||||
|
const isString = abstractType === 'string' |
||||||
|
const isTextArea = uiDatatype === UITypes.LongText |
||||||
|
const isInt = abstractType === 'integer' |
||||||
|
const isFloat = abstractType === 'float' |
||||||
|
const isDate = abstractType === 'date' || uiDatatype === 'Date' |
||||||
|
const isTime = abstractType === 'time' || uiDatatype === 'Time' |
||||||
|
const isDateTime = abstractType === 'datetime' || uiDatatype === 'DateTime' |
||||||
|
const isJSON = uiDatatype === 'JSON' |
||||||
|
const isEnum = uiDatatype === 'SingleSelect' |
||||||
|
const isSet = uiDatatype === 'MultiSelect' |
||||||
|
const isURL = uiDatatype === 'URL' |
||||||
|
const isEmail = uiDatatype === UITypes.Email |
||||||
|
const isAttachment = uiDatatype === 'Attachment' |
||||||
|
const isRating = uiDatatype === UITypes.Rating |
||||||
|
const isCurrency = uiDatatype === 'Currency' |
||||||
|
const isDuration = uiDatatype === UITypes.Duration |
||||||
|
const isAutoSaved = [ |
||||||
|
UITypes.SingleLineText, |
||||||
|
UITypes.LongText, |
||||||
|
UITypes.PhoneNumber, |
||||||
|
UITypes.Email, |
||||||
|
UITypes.URL, |
||||||
|
UITypes.Number, |
||||||
|
UITypes.Decimal, |
||||||
|
UITypes.Percent, |
||||||
|
UITypes.Count, |
||||||
|
UITypes.AutoNumber, |
||||||
|
UITypes.SpecificDBType, |
||||||
|
UITypes.Geometry, |
||||||
|
].includes(uiDatatype) |
||||||
|
const isManualSaved = [ |
||||||
|
UITypes.Currency, |
||||||
|
UITypes.Year, |
||||||
|
UITypes.Time, |
||||||
|
UITypes.Duration, |
||||||
|
].includes(uiDatatype) |
||||||
|
|
||||||
|
return { |
||||||
|
abstractType, |
||||||
|
dataTypeLow, |
||||||
|
isBoolean, |
||||||
|
isString, |
||||||
|
isTextArea, |
||||||
|
isInt, |
||||||
|
isFloat, |
||||||
|
isDate, |
||||||
|
isTime, |
||||||
|
isDateTime, |
||||||
|
isJSON, |
||||||
|
isEnum, |
||||||
|
isSet, |
||||||
|
isURL, |
||||||
|
isEmail, |
||||||
|
isAttachment, |
||||||
|
isRating, |
||||||
|
isCurrency, |
||||||
|
isDuration, |
||||||
|
isAutoSaved, |
||||||
|
isManualSaved, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<v-layout> |
||||||
|
<v-app-bar color="" /> |
||||||
|
<slot /> |
||||||
|
</v-layout> |
||||||
|
</template> |
Loading…
Reference in new issue