Skip to content

Commit

Permalink
Merge pull request #844 from nextcloud/poc-multiple-tables
Browse files Browse the repository at this point in the history
Contexts in left navigation sidebar, edit and create modal
  • Loading branch information
enjeck authored Mar 14, 2024
2 parents b9e9e42 + 981c800 commit 3aac5fa
Show file tree
Hide file tree
Showing 18 changed files with 1,105 additions and 43 deletions.
1 change: 1 addition & 0 deletions cypress/e2e/tables-archive.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('Archive tables/views', () => {
beforeEach(function() {
cy.login(localUser)
cy.visit('apps/tables')
cy.wait(1000)
})

it('can archive tables', () => {
Expand Down
1 change: 1 addition & 0 deletions cypress/e2e/tables-favorite.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('Favorite tables/views', () => {
beforeEach(function() {
cy.login(localUser)
cy.visit('apps/tables')
cy.wait(1000)
})

it('can favorite tables', () => {
Expand Down
8 changes: 6 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export default {
}
},
computed: {
...mapState(['tablesLoading']),
...mapState(['tablesLoading', 'contextsLoading']),
somethingIsLoading() {
return this.tablesLoading || this.loading
return this.tablesLoading || this.contextsLoading || this.loading
},
},
watch: {
Expand All @@ -50,6 +50,7 @@ export default {
},
async created() {
await this.$store.dispatch('loadTablesFromBE')
await this.$store.dispatch('getAllContexts')
await this.$store.dispatch('loadViewsSharedWithMeFromBE')
this.routing(this.$router.currentRoute)
this.observeAppContent()
Expand All @@ -67,6 +68,9 @@ export default {
} else if (currentRoute.path.startsWith('/view/')) {
this.$store.commit('setActiveViewId', parseInt(currentRoute.params.viewId))
this.setPageTitle(this.$store.getters.activeView.title)
} else if (currentRoute.path.startsWith('/application/')) {
this.$store.commit('setActiveContextId', parseInt(currentRoute.params.contextId))
this.setPageTitle(this.$store.getters.activeContext.name)
}
},
setPageTitle(title) {
Expand Down
6 changes: 5 additions & 1 deletion src/modules/main/sections/DataTable.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<div v-if="hasViews" class="row space-T">
<div class="col-4 space-L">
<div v-if="showOptions" class="col-4 space-L">
<h2>
{{ t('tables', 'Data') }}&nbsp;&nbsp;
<NcActions :force-menu="true" type="secondary">
Expand Down Expand Up @@ -194,6 +194,10 @@ export default {
type: Array,
default: null,
},
showOptions: {
type: Boolean,
default: true,
},
},
data() {
Expand Down
71 changes: 71 additions & 0 deletions src/modules/main/sections/TableWrapper.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<template>
<div>
<ElementDescription :active-element="table" :view-setting.sync="localViewSetting" />
<DataTable :show-options="false" :table="table" :columns="columns" :rows="rows" :view-setting.sync="localViewSetting"
@create-column="$emit('create-column')"
@import="$emit('import')"
@download-csv="$emit('download-csv')"
@toggle-share="$emit('toggle-share')"
@show-integration="$emit('show-integration')"
@create-view="createView" />
</div>
</template>

<script>
import ElementDescription from './ElementDescription.vue'
import DataTable from './DataTable.vue'
import { mapState } from 'vuex'
import { emit } from '@nextcloud/event-bus'
export default {
components: {
ElementDescription,
DataTable,
},
props: {
table: {
type: Object,
default: null,
},
columns: {
type: Array,
default: null,
},
rows: {
type: Array,
default: null,
},
viewSetting: {
type: Object,
default: null,
},
},
data() {
return {
localViewSetting: this.viewSetting,
}
},
computed: {
...mapState(['views']),
hasViews() {
return this.views.some(v => v.tableId === this.table.id)
},
},
watch: {
localViewSetting() {
this.$emit('update:viewSetting', this.localViewSetting)
},
viewSetting() {
this.localViewSetting = this.viewSetting
},
},
methods: {
createView() {
emit('tables:view:create', { tableId: this.table.id, viewSetting: this.viewSetting.length > 0 ? this.viewSetting : this.localViewSetting })
},
},
}
</script>
148 changes: 148 additions & 0 deletions src/modules/modals/CreateContext.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<template>
<NcModal v-if="showModal" size="normal" @close="actionCancel">
<div class="modal__content">
<div class="row">
<div class="col-4">
<h2>{{ t('tables', 'Create an application') }}</h2>
</div>
</div>
<div class="row space-T">
<div class="col-4 mandatory">
{{ t('tables', 'Title') }}
</div>
<div class="col-4" style="display: inline-flex;">
<!-- TODO replace with Context's icon picker -->
<NcEmojiPicker :close-on-select="true" @select="setIcon">
<NcButton type="tertiary" :aria-label="t('tables', 'Select icon for the application')"
:title="t('tables', 'Select icon')" @click.prevent>
{{ icon }}
</NcButton>
</NcEmojiPicker>
<input v-model="title" :class="{ missing: errorTitle }" type="text"
:placeholder="t('tables', 'Title of the new application')" @input="titleChangedManually">
</div>
</div>
<div class="col-4 row space-T">
<div class="col-4">
{{ t('tables', 'Description') }}
</div>
<input v-model="description" type="text"
:placeholder="t('tables', 'Description of the new application')">
</div>
<div class="col-4 row space-T">
<div class="col-4">
{{ t('tables', 'Resources') }}
</div>
<NcContextResource :resources.sync="resources" />
</div>
<div class="row space-R">
<div class="fix-col-4 end">
<NcButton type="primary" :aria-label="t('tables', 'Create application')" @click="submit">
{{ t('tables', 'Create application') }}
</NcButton>
</div>
</div>
</div>
</NcModal>
</template>

<script>
import { NcModal, NcEmojiPicker, NcButton } from '@nextcloud/vue'
import { showError } from '@nextcloud/dialogs'
import '@nextcloud/dialogs/dist/index.css'
import NcContextResource from '../../shared/components/ncContextResource/NcContextResource.vue'
export default {
name: 'CreateContext',
components: {
NcModal,
NcEmojiPicker,
NcButton,
NcContextResource,
},
props: {
showModal: {
type: Boolean,
default: false,
},
},
data() {
return {
title: '',
icon: '😀',
customIconChosen: false,
customTitleChosen: false,
errorTitle: false,
description: '',
resources: [],
}
},
watch: {
title() {
if (this.title.length >= 200) {
showError(t('tables', 'The title limit is reached with 200 characters. Please use a shorter title.'))
this.title = this.title.slice(0, 199)
}
},
},
methods: {
titleChangedManually() {
this.customTitleChosen = true
},
setIcon(icon) {
this.icon = icon
this.customIconChosen = true
},
actionCancel() {
this.reset()
this.$emit('close')
},
async submit() {
if (this.title === '') {
showError(t('tables', 'Cannot create new context. Title is missing.'))
this.errorTitle = true
} else {
const newContextId = await this.sendNewContextToBE()
if (newContextId) {
await this.$router.push('/application/' + newContextId)
this.actionCancel()
}
}
},
async sendNewContextToBE() {
const dataResources = this.resources.map(resource => {
return {
id: parseInt(resource.id),
type: parseInt(resource.nodeType),
permissions: 660,
}
})
const data = {
name: this.title,
iconName: this.icon,
description: this.description,
nodes: dataResources,
}
const res = await this.$store.dispatch('insertNewContext', { data })
if (res) {
return res.id
} else {
showError(t('tables', 'Could not create new table'))
}
},
reset() {
this.title = ''
this.errorTitle = false
this.icon = '😀'
this.customIconChosen = false
this.customTitleChosen = false
},
},
}
</script>

<style lang="scss" scoped>
.modal__content {
padding-right: 0 !important;
}
</style>
Loading

0 comments on commit 3aac5fa

Please sign in to comment.