<template> <div class="api-docs"> <div ref="header" class="api-docs__header"> <nuxt-link :to="{ name: 'index' }" class="api-docs__logo"> <img src="@baserow/modules/core/static/img/logo.svg" alt="" /> </nuxt-link> <a ref="databasesToggle" class="api-docs__switch" @click.prevent="databasesOpen = !databasesOpen" > <i class="api-docs__switch-icon iconoir-db"></i> {{ $t('apiDocsDatabase.pageTitle', database) }} </a> <div class="api-docs__open"> <nuxt-link v-if="database.tables.length > 0" :to="{ name: 'database-table', params: { databaseId: database.id, tableId: database.tables[0].id, }, }" class="button button--ghost" >{{ $t('apiDocsDatabase.openDatabase') }}</nuxt-link > </div> </div> <div v-show="databasesOpen" ref="databases" class="api-docs__databases"> <div class="api-docs__databases-inner"> <APIDocsSelectDatabase :selected="database.id" /> <nuxt-link :to="{ name: 'dashboard' }" class="select-application__back"> <i class="iconoir-arrow-left"></i> {{ $t('apiDocsDatabase.back') }} </nuxt-link> </div> </div> <APIDocsMenu :database="database" :navigate="navigate" :nav-active="navActive" /> <div class="api-docs__body"> <APIDocsIntro :database="database" /> <APIDocsAuth v-model="exampleData" /> <div v-for="table in database.tables" :key="table.id"> <APIDocsTableFields v-if="fields" :table="table" :fields="fields" :navigate="navigate" /> <APIDocsTableListFields v-model="exampleData" :table="table" :fields="fields" /> <APIDocsTableListRows v-model="exampleData" :table="table" :navigate="navigate" :get-list-url="getListURL" :get-response-item="getResponseItem" :get-field-mapping="getFieldMapping" /> <APIDocsTableGetRow v-model="exampleData" :table="table" :get-item-url="getItemURL" :get-response-item="getResponseItem" :get-field-mapping="getFieldMapping" /> <APIDocsTableCreateRow v-model="exampleData" :table="table" :without-read-only="withoutReadOnly" :user-field-names="exampleData.userFieldNames" :get-list-url="getListURL" :get-request-example="getRequestExample" :get-batch-request-example="getBatchRequestExample" :get-batch-response-item="getBatchResponseItems" :get-response-item="getResponseItem" :get-field-mapping="getFieldMapping" /> <APIDocsTableUpdateRow v-model="exampleData" :table="table" :without-read-only="withoutReadOnly" :user-field-names="exampleData.userFieldNames" :get-item-url="getItemURL" :get-list-url="getListURL" :get-request-example="getRequestExample" :get-batch-request-example="getBatchRequestExample" :get-batch-response-item="getBatchResponseItems" :get-response-item="getResponseItem" :get-field-mapping="getFieldMapping" /> <APIDocsTableMoveRow v-model="exampleData" :table="table" :user-field-names="exampleData.userFieldNames" :get-item-url="getItemURL" :get-response-item="getResponseItem" :get-field-mapping="getFieldMapping" /> <APIDocsTableDeleteRow v-model="exampleData" :table="table" :get-item-url="getItemURL" :get-delete-list-url="getDeleteListURL" :get-batch-delete-request-example="getBatchDeleteRequestExample" /> </div> <APIDocsUploadFile v-model="exampleData" :get-upload-file-list-url="getUploadFileListUrl" :get-upload-file-example="getUploadFileExample" :get-upload-file-response="getUploadFileResponse" /> <APIDocsUploadFileViaURL v-model="exampleData" :get-upload-file-response="getUploadFileResponse" :get-upload-file-via-url-list-url="getUploadFileViaUrlListUrl" :get-upload-file-via-url-request-example=" getUploadFileViaUrlRequestExample " /> <APIDocsFilters /> <APIDocsErrors v-model="exampleData" /> </div> </div> </template> <script> import { isElement } from '@baserow/modules/core/utils/dom' import APIDocsSelectDatabase from '@baserow/modules/database/components/docs/APIDocsSelectDatabase' import { DatabaseApplicationType } from '@baserow/modules/database/applicationTypes' import FieldService from '@baserow/modules/database/services/field' // All sections import APIDocsIntro from '@baserow/modules/database/components/docs/sections/APIDocsIntro' import APIDocsAuth from '@baserow/modules/database/components/docs/sections/APIDocsAuth' import APIDocsTableFields from '@baserow/modules/database/components/docs/sections/APIDocsTableFields' import APIDocsTableListFields from '@baserow/modules/database/components/docs/sections/APIDocsTableListFields' import APIDocsTableListRows from '@baserow/modules/database/components/docs/sections/APIDocsTableListRows' import APIDocsTableGetRow from '@baserow/modules/database/components/docs/sections/APIDocsTableGetRow' import APIDocsTableCreateRow from '@baserow/modules/database/components/docs/sections/APIDocsTableCreateRow' import APIDocsTableUpdateRow from '@baserow/modules/database/components/docs/sections/APIDocsTableUpdateRow' import APIDocsTableMoveRow from '@baserow/modules/database/components/docs/sections/APIDocsTableMoveRow' import APIDocsTableDeleteRow from '@baserow/modules/database/components/docs/sections/APIDocsTableDeleteRow' import APIDocsUploadFile from '@baserow/modules/database/components/docs/sections/APIDocsUploadFile' import APIDocsUploadFileViaURL from '@baserow/modules/database/components/docs/sections/APIDocsUploadFileViaURL' import APIDocsFilters from '@baserow/modules/database/components/docs/sections/APIDocsFilters' import APIDocsErrors from '@baserow/modules/database/components/docs/sections/APIDocsErrors' import APIDocsMenu from '@baserow/modules/database/components/docs/sections/APIDocsMenu.vue' // Re-use the FileFieldType docs response example. import { FileFieldType } from '../fieldTypes' export default { name: 'APIDocsDatabase', components: { APIDocsSelectDatabase, APIDocsIntro, APIDocsAuth, APIDocsTableFields, APIDocsTableListFields, APIDocsTableListRows, APIDocsTableGetRow, APIDocsTableCreateRow, APIDocsTableUpdateRow, APIDocsTableMoveRow, APIDocsTableDeleteRow, APIDocsUploadFile, APIDocsUploadFileViaURL, APIDocsFilters, APIDocsErrors, APIDocsMenu, }, middleware: ['authenticated', 'workspacesAndApplications'], async asyncData({ store, params, error, app }) { const databaseId = parseInt(params.databaseId) const database = store.getters['application/get'](databaseId) const type = DatabaseApplicationType.getType() if (database === undefined || database.type !== type) { return error({ statusCode: 404, message: 'Database not found.' }) } const fieldData = {} for (const i in database.tables) { const table = database.tables[i] const { data } = await FieldService(app.$client).fetchAll(table.id) fieldData[table.id] = data } return { database, fieldData } }, data() { return { exampleData: { // Indicates which request example type is shown. type: 'curl', userFieldNames: true, }, // Indicates which navigation item is active. navActive: '', // Indicates if the databases sidebar is open. databasesOpen: false, } }, head() { return { title: this.$t('apiDocsDatabase.pageTitle', this.database), } }, computed: { userFieldNamesParam() { return this.exampleData.userFieldNames ? '?user_field_names=true' : '' }, fields() { return Object.fromEntries( Object.entries(this.fieldData).map(([key, fields]) => { return [key, fields.map((field) => this.populateField(field))] }) ) // return this.fieldData.map((field) => populateField(field)) }, withoutReadOnly() { return Object.fromEntries( Object.entries(this.fieldData).map(([key, fields]) => { return [key, fields.filter((field) => !field._.isReadOnly)] }) ) }, }, mounted() { // When the user clicks outside the databases sidebar and it is open then it must // be closed. this.$el.clickOutsideEvent = (event) => { if ( this.databasesOpen && !isElement(this.$refs.databasesToggle, event.target) && !isElement(this.$refs.databases, event.target) ) { this.databasesOpen = false } } document.body.addEventListener('click', this.$el.clickOutsideEvent) // When the user scrolls in the body or when the window is resized, the active // navigation item must be updated. this.$el.scrollEvent = () => this.updateNav() this.$el.resizeEvent = () => this.updateNav() window.addEventListener('scroll', this.$el.scrollEvent) window.addEventListener('resize', this.$el.resizeEvent) this.updateNav() }, beforeDestroy() { document.body.removeEventListener('click', this.$el.clickOutsideEvent) window.removeEventListener('scroll', this.$el.scrollEvent) window.removeEventListener('resize', this.$el.resizeEvent) }, methods: { /** * Add metadata to fields */ populateField(field) { const fieldType = this.$registry.get('field', field.type) field._ = { type: fieldType.getDocsDataType(field), description: fieldType.getDocsDescription(field), requestExample: fieldType.getDocsRequestExample(field), responseExample: fieldType.getDocsResponseExample(field), fieldResponseExample: fieldType.getDocsFieldResponseExample( field, fieldType.isReadOnly ), isReadOnly: fieldType.isReadOnly, } return field }, /** * Called when the user scrolls or when the window is resized. It will check which * navigation item is active based on the scroll position of the available ids. */ updateNav() { const body = document.documentElement const sections = body.querySelectorAll('[id]') sections.forEach((section, index) => { const top = section.offsetTop const nextIndex = (index + 1).toString() const next = nextIndex in sections ? sections[nextIndex].offsetTop : body.scrollHeight if (top <= body.scrollTop && body.scrollTop < next) { this.navActive = section.id } }) }, navigate(to) { const section = document.querySelector(`[id='${to}']`) document.documentElement.scrollTop = section.offsetTop - 20 + this.$refs.header.clientHeight }, /** * Generates an example request object based on the available fields of the table. */ getRequestExample(table, response = false, includeId = false) { const item = {} // In case we are creating a sample response // read only fields need to be included. // They should be left out in the case of // creating a sample request. let fieldsToLoopOver = this.fields[table.id] if (!response) { fieldsToLoopOver = fieldsToLoopOver.filter( (field) => !field._.isReadOnly ) } if (includeId) { item.id = 0 } fieldsToLoopOver.forEach((field) => { const example = response ? field._.responseExample : field._.requestExample if (this.exampleData.userFieldNames) { item[field.name] = example } else { item[`field_${field.id}`] = example } }) return item }, /** * Generates an example request object when providing multiple items. */ getBatchRequestExample(table, response = false) { return { items: [this.getRequestExample(table, response, true)], } }, /** * Generates an example request object for deleting multiple items. */ getBatchDeleteRequestExample(table, response = false) { return { items: [0], } }, /** * Generates an example response object based on the available fields of the table. */ getResponseItem(table) { const item = { id: 0, order: '1.00000000000000000000' } Object.assign(item, this.getRequestExample(table, true)) return item }, /** * Generates an example response object when multiple items are returned. */ getBatchResponseItems(table) { return { items: [this.getResponseItem(table)], } }, /** * Returns the mapping of the field id as key and the field name as value. */ getFieldMapping(table) { const mapping = {} this.fields[table.id].forEach((field) => { if (this.exampleData.userFieldNames) { mapping[field.name] = `field_${field.id}` } else { mapping[`field_${field.id}`] = field.name } }) return mapping }, getListURL(table, addUserFieldParam, batch = false) { return `${this.$config.PUBLIC_BACKEND_URL}/api/database/rows/table/${ table.id }/${batch ? 'batch/' : ''}${ addUserFieldParam ? this.userFieldNamesParam : '' }` }, getDeleteListURL(table) { return `${this.$config.PUBLIC_BACKEND_URL}/api/database/rows/table/${table.id}/batch-delete/` }, /** * Generates the 'upload file' file example. */ getUploadFileExample() { return 'photo.png' }, /** * Generates the 'upload file' and 'upload via URL' file example response. */ getUploadFileResponse() { return this.$registry .get('field', FileFieldType.getType()) .getDocsResponseExample()[0] }, /** * Generates the 'upload file' URI. */ getUploadFileListUrl() { return this.$config.PUBLIC_BACKEND_URL + '/api/user-files/upload-file/' }, /** * Generates the 'upload file' request example. */ getUploadFileViaUrlRequestExample() { return { url: 'https://baserow.io/assets/photo.png', } }, /** * Generates the 'upload file via URL' URI. */ getUploadFileViaUrlListUrl() { return this.$config.PUBLIC_BACKEND_URL + '/api/user-files/upload-via-url/' }, getItemURL(table, addUserFieldParam) { return ( this.getListURL(table) + '{row_id}/' + (addUserFieldParam ? this.userFieldNamesParam : '') ) }, }, } </script>