Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contexts in left navigation sidebar, edit and create modal #844

Merged
merged 28 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0a71fd6
feat(Contexts): API endpoint for getting Contexts
blizzz Feb 21, 2024
a6d0b11
feat(Contexts): API to add and remove a node to a Context
blizzz Feb 27, 2024
ffeed86
feat(Contexts): API endpoint for getting Contexts
blizzz Feb 21, 2024
5f5b8f2
feat(Contexts): API to get full context info
blizzz Feb 21, 2024
a9365d7
feat(Contexts): API to create a new Context
blizzz Feb 26, 2024
21a7d2c
show that multiple tables can be on same page
enjeck Feb 14, 2024
ea9caee
update
enjeck Feb 19, 2024
170f685
feat: show contexts
enjeck Feb 22, 2024
41da9fc
check if nodes exist
enjeck Feb 22, 2024
cb77766
fix: lint fixes and cleanup
juliusknorr Feb 28, 2024
f11a9e5
feat: contexts in nav and modal
enjeck Mar 3, 2024
afe4c77
feat: add resource in frontend
enjeck Mar 5, 2024
9148964
Improve context modals
enjeck Mar 6, 2024
b47b9b6
fix: table/view events, lint, add todos
enjeck Mar 7, 2024
ea0807b
fix: indicate when contexts are loading
enjeck Mar 7, 2024
6d70340
enh: update resources in context
enjeck Mar 8, 2024
3a4b3b1
enh: context in nav search, improve resource search
enjeck Mar 9, 2024
20a08cf
enh: remove /context/ route
enjeck Mar 9, 2024
93068d0
enh: modify styling, lint
enjeck Mar 11, 2024
d4c05ac
enh: rename user-facing text
enjeck Mar 11, 2024
9c7db53
enh: check user is owner to manage context
enjeck Mar 11, 2024
69293e0
enh: edit context modal, redirect non-existent context
enjeck Mar 11, 2024
beeb7ed
enh: improvements
enjeck Mar 11, 2024
9817e2e
enh: modify styling and text for Context
enjeck Mar 12, 2024
42a0986
enh: use formatted options in resource NcSelect
enjeck Mar 12, 2024
b2dd259
fix: lint
enjeck Mar 12, 2024
a953fdb
fix: lint
enjeck Mar 13, 2024
981c800
fix(Cypress): wait for button to render
enjeck Mar 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading