diff --git a/backend/src/baserow/contrib/dashboard/widgets/registries.py b/backend/src/baserow/contrib/dashboard/widgets/registries.py index 2a4dd7b21..ec56a291d 100644 --- a/backend/src/baserow/contrib/dashboard/widgets/registries.py +++ b/backend/src/baserow/contrib/dashboard/widgets/registries.py @@ -1,6 +1,7 @@ from abc import ABC from decimal import Decimal +from baserow.contrib.dashboard.models import Dashboard from baserow.contrib.dashboard.types import WidgetDict from baserow.core.registry import ( CustomFieldsInstanceMixin, @@ -32,6 +33,17 @@ class WidgetType( id_mapping_name = DASHBOARD_WIDGETS allowed_fields = ["title", "description"] + def before_create(self, dashboard: Dashboard): + """ + This function allows you to perform checks and operations + before a widget is created. + + :param dashboard: The dashboard where the widget should be + created. + """ + + pass + def prepare_value_for_db(self, values: dict, instance: Widget | None = None): """ This function allows you to hook into the moment a widget is created or diff --git a/backend/src/baserow/contrib/dashboard/widgets/service.py b/backend/src/baserow/contrib/dashboard/widgets/service.py index bf9ac323e..cae3a24e1 100644 --- a/backend/src/baserow/contrib/dashboard/widgets/service.py +++ b/backend/src/baserow/contrib/dashboard/widgets/service.py @@ -115,6 +115,8 @@ class WidgetService: widget_type_from_registry = widget_type_registry.get(widget_type) + widget_type_from_registry.before_create(dashboard) + new_widget = self.handler.create_widget( widget_type_from_registry, dashboard, diff --git a/enterprise/backend/src/baserow_enterprise/dashboard/widgets/widget_types.py b/enterprise/backend/src/baserow_enterprise/dashboard/widgets/widget_types.py index 2d24d1bdb..50d0328b0 100644 --- a/enterprise/backend/src/baserow_enterprise/dashboard/widgets/widget_types.py +++ b/enterprise/backend/src/baserow_enterprise/dashboard/widgets/widget_types.py @@ -1,3 +1,4 @@ +from baserow_premium.license.handler import LicenseHandler from rest_framework import serializers from baserow.contrib.dashboard.data_sources.handler import DashboardDataSourceHandler @@ -6,6 +7,7 @@ from baserow.contrib.dashboard.types import WidgetDict from baserow.contrib.dashboard.widgets.models import Widget from baserow.contrib.dashboard.widgets.registries import WidgetType from baserow.core.services.registries import service_type_registry +from baserow_enterprise.features import CHART_WIDGET from baserow_enterprise.integrations.local_baserow.service_types import ( LocalBaserowGroupedAggregateRowsUserServiceType, ) @@ -31,6 +33,11 @@ class ChartWidgetType(WidgetType): class SerializedDict(WidgetDict): data_source_id: int + def before_create(self, dashboard): + LicenseHandler.raise_if_workspace_doesnt_have_feature( + CHART_WIDGET, dashboard.workspace + ) + def prepare_value_for_db(self, values: dict, instance: Widget | None = None): if instance is None: # When the widget is being created we want to automatically diff --git a/enterprise/backend/src/baserow_enterprise/features.py b/enterprise/backend/src/baserow_enterprise/features.py index a3adb639e..f650a0afb 100644 --- a/enterprise/backend/src/baserow_enterprise/features.py +++ b/enterprise/backend/src/baserow_enterprise/features.py @@ -7,3 +7,4 @@ METRICS = "metrics" SECURE_FILE_SERVE = "secure_file_serve" ENTERPRISE_SETTINGS = "ENTERPRISE_SETTINGS" DATA_SYNC = "data_sync" +CHART_WIDGET = "chart_widget" diff --git a/enterprise/backend/src/baserow_enterprise/license_types.py b/enterprise/backend/src/baserow_enterprise/license_types.py index d50dea130..1ed41d93e 100755 --- a/enterprise/backend/src/baserow_enterprise/license_types.py +++ b/enterprise/backend/src/baserow_enterprise/license_types.py @@ -7,6 +7,7 @@ from baserow_premium.license.registries import LicenseType, SeatUsageSummary from baserow.core.models import Workspace from baserow_enterprise.features import ( AUDIT_LOG, + CHART_WIDGET, DATA_SYNC, ENTERPRISE_SETTINGS, RBAC, @@ -32,6 +33,7 @@ class EnterpriseWithoutSupportLicenseType(LicenseType): SECURE_FILE_SERVE, ENTERPRISE_SETTINGS, DATA_SYNC, + CHART_WIDGET, ] instance_wide = True seats_manually_assigned = False diff --git a/enterprise/backend/tests/baserow_enterprise_tests/api/dashboard/test_chart_widget_type_views.py b/enterprise/backend/tests/baserow_enterprise_tests/api/dashboard/test_chart_widget_type_views.py index 550188b7f..5fb5c01ad 100644 --- a/enterprise/backend/tests/baserow_enterprise_tests/api/dashboard/test_chart_widget_type_views.py +++ b/enterprise/backend/tests/baserow_enterprise_tests/api/dashboard/test_chart_widget_type_views.py @@ -1,3 +1,5 @@ +from django.test.utils import override_settings + import pytest from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK @@ -6,7 +8,9 @@ from baserow.test_utils.helpers import AnyInt @pytest.mark.django_db +@override_settings(DEBUG=True) def test_create_chart_widget(api_client, enterprise_data_fixture): + enterprise_data_fixture.enable_enterprise() user, token = enterprise_data_fixture.create_user_and_token() dashboard = enterprise_data_fixture.create_dashboard_application(user=user) diff --git a/enterprise/backend/tests/baserow_enterprise_tests/dashboard/test_chart_widget_type.py b/enterprise/backend/tests/baserow_enterprise_tests/dashboard/test_chart_widget_type.py index 51bac853c..1bd77fcfb 100644 --- a/enterprise/backend/tests/baserow_enterprise_tests/dashboard/test_chart_widget_type.py +++ b/enterprise/backend/tests/baserow_enterprise_tests/dashboard/test_chart_widget_type.py @@ -1,5 +1,6 @@ from django.contrib.contenttypes.models import ContentType from django.db.models.deletion import ProtectedError +from django.test.utils import override_settings import pytest @@ -14,7 +15,9 @@ from baserow_enterprise.integrations.local_baserow.models import ( @pytest.mark.django_db +@override_settings(DEBUG=True) def test_create_chart_widget_creates_data_source(enterprise_data_fixture): + enterprise_data_fixture.enable_enterprise() user = enterprise_data_fixture.create_user() dashboard = enterprise_data_fixture.create_dashboard_application(user=user) widget_type = "chart" diff --git a/enterprise/web-frontend/modules/baserow_enterprise/assets/images/dashboard/widgets/chart_widget.svg b/enterprise/web-frontend/modules/baserow_enterprise/assets/images/dashboard/widgets/chart_widget.svg new file mode 100644 index 000000000..7dc020d8e --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/assets/images/dashboard/widgets/chart_widget.svg @@ -0,0 +1,14 @@ +<svg width="72" height="48" viewBox="0 0 72 48" fill="none" xmlns="http://www.w3.org/2000/svg"> + <rect x="1.25" y="1.25" width="69.5" height="45.5" rx="4.75" fill="white"/> + <rect x="1.25" y="1.25" width="69.5" height="45.5" rx="4.75" stroke="#E6E6E7" stroke-width="1.5"/> + <rect opacity="0.48" x="8" y="15.5" width="6" height="4" rx="2" fill="#E6E6E7"/> + <rect opacity="0.48" x="8" y="37" width="6" height="4" rx="2" fill="#E6E6E7"/> + <rect opacity="0.48" x="8" y="26.5" width="8" height="4" rx="2" fill="#E6E6E7"/> + <rect x="24" y="8" width="1" height="32" fill="#EDEDED"/> + <rect x="20" y="39" width="44" height="1" fill="#EDEDED"/> + <rect x="20" y="28" width="44" height="1" fill="#EDEDED"/> + <rect x="20" y="17" width="44" height="1" fill="#EDEDED"/> + <path d="M30 37C30 35.8954 30.8954 35 32 35H34C35.1046 35 36 35.8954 36 37V40H30V37Z" fill="#4E5CFE"/> + <path d="M42 25C42 23.8954 42.8954 23 44 23H46C47.1046 23 48 23.8954 48 25V40H42V25Z" fill="#4E5CFE"/> + <path d="M54 13C54 11.8954 54.8954 11 56 11H58C59.1046 11 60 11.8954 60 13V40H54V13Z" fill="#4E5CFE"/> +</svg> diff --git a/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/all.scss b/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/all.scss index c55e374c4..7e9a4aa2d 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/all.scss +++ b/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/all.scss @@ -18,3 +18,4 @@ @import 'common_oidc_setting_form'; @import 'saml_auth_link'; @import 'oidc_auth_link'; +@import 'dashboard_chart_widget'; diff --git a/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/dashboard_chart_widget.scss b/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/dashboard_chart_widget.scss new file mode 100644 index 000000000..956940714 --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/assets/scss/components/dashboard_chart_widget.scss @@ -0,0 +1,4 @@ +.dashboard-chart-widget { + padding: 0 24px 24px; +} + diff --git a/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/data_source/GroupedAggregateRowsDataSourceForm.vue b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/data_source/GroupedAggregateRowsDataSourceForm.vue new file mode 100644 index 000000000..ee41ede54 --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/data_source/GroupedAggregateRowsDataSourceForm.vue @@ -0,0 +1,29 @@ +<template><div></div></template> + +<script> +import form from '@baserow/modules/core/mixins/form' + +export default { + name: 'GroupedAggregateRowsDataSourceForm', + mixins: [form], + props: { + dashboard: { + type: Object, + required: true, + }, + widget: { + type: Object, + required: true, + }, + dataSource: { + type: Object, + required: true, + }, + storePrefix: { + type: String, + required: false, + default: '', + }, + }, +} +</script> diff --git a/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidget.vue b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidget.vue new file mode 100644 index 000000000..251858f6a --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidget.vue @@ -0,0 +1,83 @@ +<template> + <div class="dashboard-chart-widget"> + <div class="widget-header"> + <div class="widget-header__main"> + <div class="widget-header__title-wrapper"> + <div class="widget-header__title">{{ widget.title }}</div> + <div + v-if="dataSourceMisconfigured" + class="widget-header__fix-configuration" + > + <svg + width="5" + height="6" + viewBox="0 0 5 6" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <circle cx="2.5" cy="3" r="2.5" fill="#FF5A44" /> + </svg> + {{ $t('widget.fixConfiguration') }} + </div> + </div> + <div v-if="widget.description" class="widget-header__description"> + {{ widget.description }} + </div> + </div> + <WidgetContextMenu + v-if="isEditMode" + :widget="widget" + :dashboard="dashboard" + @delete-widget="$emit('delete-widget', $event)" + ></WidgetContextMenu> + </div> + </div> +</template> + +<script> +import WidgetContextMenu from '@baserow/modules/dashboard/components/widget/WidgetContextMenu' + +export default { + name: 'ChartWidget', + components: { WidgetContextMenu }, + props: { + dashboard: { + type: Object, + required: true, + }, + widget: { + type: Object, + required: true, + }, + storePrefix: { + type: String, + required: false, + default: '', + }, + }, + computed: { + dataSource() { + return this.$store.getters[ + `${this.storePrefix}dashboardApplication/getDataSourceById` + ](this.widget.data_source_id) + }, + dataForDataSource() { + return this.$store.getters[ + `${this.storePrefix}dashboardApplication/getDataForDataSource` + ](this.dataSource?.id) + }, + isEditMode() { + return this.$store.getters[ + `${this.storePrefix}dashboardApplication/isEditMode` + ] + }, + dataSourceMisconfigured() { + const data = this.dataForDataSource + if (data) { + return !!data._error + } + return false + }, + }, +} +</script> diff --git a/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidgetSettings.vue b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidgetSettings.vue new file mode 100644 index 000000000..c3e98fb1e --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/widget/ChartWidgetSettings.vue @@ -0,0 +1,75 @@ +<template> + <GroupedAggregateRowsDataSourceForm + v-if="dataSource" + ref="dataSourceForm" + :dashboard="dashboard" + :widget="widget" + :data-source="dataSource" + :default-values="dataSource" + :store-prefix="storePrefix" + @values-changed="onDataSourceValuesChanged" + /> +</template> + +<script> +import GroupedAggregateRowsDataSourceForm from '@baserow_enterprise/dashboard/components/data_source/GroupedAggregateRowsDataSourceForm' +import error from '@baserow/modules/core/mixins/error' +import { notifyIf } from '@baserow/modules/core/utils/error' + +export default { + name: 'ChartWidgetSettings', + components: { GroupedAggregateRowsDataSourceForm }, + mixins: [error], + props: { + dashboard: { + type: Object, + required: true, + }, + widget: { + type: Object, + required: true, + }, + storePrefix: { + type: String, + required: false, + default: '', + }, + }, + data() { + return { + loading: false, + } + }, + computed: { + dataSource() { + return this.$store.getters[ + `${this.storePrefix}dashboardApplication/getDataSourceById` + ](this.widget.data_source_id) + }, + integration() { + return this.$store.getters[ + `${this.storePrefix}dashboardApplication/getIntegrationById` + ](this.dataSource.integration_id) + }, + }, + methods: { + async onDataSourceValuesChanged(changedDataSourceValues) { + if (this.$refs.dataSourceForm.isFormValid()) { + try { + await this.$store.dispatch( + `${this.storePrefix}dashboardApplication/updateDataSource`, + { + dataSourceId: this.dataSource.id, + values: changedDataSourceValues, + } + ) + } catch (error) { + this.$refs.dataSourceForm.reset() + this.$refs.dataSourceForm.touch() + notifyIf(error, 'dashboard') + } + } + }, + }, +} +</script> diff --git a/enterprise/web-frontend/modules/baserow_enterprise/dashboard/widgetTypes.js b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/widgetTypes.js new file mode 100644 index 000000000..8394a6799 --- /dev/null +++ b/enterprise/web-frontend/modules/baserow_enterprise/dashboard/widgetTypes.js @@ -0,0 +1,44 @@ +import { WidgetType } from '@baserow/modules/dashboard/widgetTypes' +import ChartWidget from '@baserow_enterprise/dashboard/components/widget/ChartWidget' +import ChartWidgetSettings from '@baserow_enterprise/dashboard/components/widget/ChartWidgetSettings' +import ChartWidgetSvg from '@baserow_enterprise/assets/images/dashboard/widgets/chart_widget.svg' +import EnterpriseFeatures from '@baserow_enterprise/features' +import EnterpriseModal from '@baserow_enterprise/components/EnterpriseModal' + +export class ChartWidgetType extends WidgetType { + static getType() { + return 'chart' + } + + get name() { + return this.app.i18n.t('chartWidget.name') + } + + get createWidgetImage() { + return ChartWidgetSvg + } + + get component() { + return ChartWidget + } + + get settingsComponent() { + return ChartWidgetSettings + } + + isLoading(widget, data) { + const dataSourceId = widget.data_source_id + if (data[dataSourceId] && Object.keys(data[dataSourceId]).length !== 0) { + return false + } + return true + } + + isAvailable(workspaceId) { + return this.app.$hasFeature(EnterpriseFeatures.CHART_WIDGET, workspaceId) + } + + getDeactivatedModal() { + return EnterpriseModal + } +} diff --git a/enterprise/web-frontend/modules/baserow_enterprise/features.js b/enterprise/web-frontend/modules/baserow_enterprise/features.js index bd4a7e2d3..151681e00 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/features.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/features.js @@ -6,6 +6,7 @@ const EnterpriseFeatures = { AUDIT_LOG: 'AUDIT_LOG', ENTERPRISE_SETTINGS: 'ENTERPRISE_SETTINGS', DATA_SYNC: 'DATA_SYNC', + CHART_WIDGET: 'CHART_WIDGET', } export default EnterpriseFeatures diff --git a/enterprise/web-frontend/modules/baserow_enterprise/licenseTypes.js b/enterprise/web-frontend/modules/baserow_enterprise/licenseTypes.js index 218b82627..d1b2cd7e4 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/licenseTypes.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/licenseTypes.js @@ -44,6 +44,7 @@ export class EnterpriseWithoutSupportLicenseType extends LicenseType { EnterpriseFeaturesObject.AUDIT_LOG, EnterpriseFeaturesObject.ENTERPRISE_SETTINGS, EnterpriseFeaturesObject.DATA_SYNC, + EnterpriseFeaturesObject.CHART_WIDGET, ] } diff --git a/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json b/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json index 54c0d08cf..666aded50 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json +++ b/enterprise/web-frontend/modules/baserow_enterprise/locales/en.json @@ -439,5 +439,8 @@ }, "oidcAuthLink": { "placeholderWithOIDC": "{login} with {provider}" + }, + "chartWidget": { + "name": "Chart" } } diff --git a/enterprise/web-frontend/modules/baserow_enterprise/plugin.js b/enterprise/web-frontend/modules/baserow_enterprise/plugin.js index fa3519eb0..814a68d2f 100644 --- a/enterprise/web-frontend/modules/baserow_enterprise/plugin.js +++ b/enterprise/web-frontend/modules/baserow_enterprise/plugin.js @@ -50,9 +50,13 @@ import { GitLabIssuesDataSyncType, HubspotContactsDataSyncType, } from '@baserow_enterprise/dataSyncTypes' +import { ChartWidgetType } from '@baserow_enterprise/dashboard/widgetTypes' import { PeriodicIntervalFieldsConfigureDataSyncType } from '@baserow_enterprise/configureDataSyncTypes' -import { FF_AB_SSO } from '@baserow/modules/core/plugins/featureFlags' +import { + FF_AB_SSO, + FF_DASHBOARDS, +} from '@baserow/modules/core/plugins/featureFlags' export default (context) => { const { app, isDev, store } = context @@ -155,4 +159,8 @@ export default (context) => { 'configureDataSync', new PeriodicIntervalFieldsConfigureDataSyncType(context) ) + + if (app.$featureFlagIsEnabled(FF_DASHBOARDS)) { + app.$registry.register('dashboardWidget', new ChartWidgetType(context)) + } } diff --git a/web-frontend/modules/core/assets/scss/components/dashboard/all.scss b/web-frontend/modules/core/assets/scss/components/dashboard/all.scss index 9e66aaffa..c19a721f5 100644 --- a/web-frontend/modules/core/assets/scss/components/dashboard/all.scss +++ b/web-frontend/modules/core/assets/scss/components/dashboard/all.scss @@ -9,3 +9,4 @@ @import 'create_widget_button'; @import 'widget_header'; @import 'widget_settings_base_form'; +@import 'create_widget_modal'; diff --git a/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_card.scss b/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_card.scss index 121ce9932..b5a250269 100644 --- a/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_card.scss +++ b/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_card.scss @@ -13,6 +13,11 @@ } .create-widget-card__name { + height: 16px; + display: flex; + flex-direction: row; + align-items: center; + gap: 6px; color: $palette-neutral-1200; font-size: 13px; font-style: normal; @@ -20,8 +25,17 @@ line-height: 20px; } +.create-widget-card__name-locked { + display: inline-block; + color: #4e5cfe; + padding: 3px; + border-radius: 4px; + background: rgba(78, 92, 254, 0.1); +} + .create-widget-card__img-container { - padding: 16px 24px; + height: 80px; + padding: 0 24px; display: flex; justify-content: center; align-items: center; @@ -31,7 +45,7 @@ box-shadow: 0 1px 2px 0 rgba(7, 8, 16, 0.1); } -.create-widget-card:hover .create-widget-card__img-container { +.create-widget-card--available:hover .create-widget-card__img-container { border: 1px solid #d7d8d9; background: #f7f7f7; } diff --git a/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_modal.scss b/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_modal.scss new file mode 100644 index 000000000..7df0efe79 --- /dev/null +++ b/web-frontend/modules/core/assets/scss/components/dashboard/create_widget_modal.scss @@ -0,0 +1,5 @@ +.create-widget-modal__cards { + display: flex; + flex-direction: row; + gap: 22px; +} diff --git a/web-frontend/modules/dashboard/components/CreateWidgetCard.vue b/web-frontend/modules/dashboard/components/CreateWidgetCard.vue new file mode 100644 index 000000000..4a3f099d2 --- /dev/null +++ b/web-frontend/modules/dashboard/components/CreateWidgetCard.vue @@ -0,0 +1,60 @@ +<template> + <a + class="create-widget-card" + :class="{ + 'create-widget-card--available': isWidgetAvailable, + }" + @click="widgetTypeSelected" + > + <div class="create-widget-card__img-container"> + <img :src="widgetType.createWidgetImage" /> + </div> + <div class="create-widget-card__name"> + <span>{{ widgetType.name }}</span> + <span v-if="!isWidgetAvailable"> + <i class="iconoir-lock create-widget-card__name-locked"></i> + </span> + </div> + <component + :is="deactivatedModal" + v-if="deactivatedModal != null" + ref="deactivatedModal" + :name="widgetType.name" + :workspace="dashboard.workspace" + ></component> + </a> +</template> + +<script> +export default { + name: 'CreateWidgetCard', + props: { + dashboard: { + type: Object, + required: true, + }, + widgetType: { + type: Object, + required: true, + }, + }, + computed: { + isWidgetAvailable() { + return this.widgetType.isAvailable(this.dashboard.workspace.id) + }, + deactivatedModal() { + return this.widgetType.getDeactivatedModal() + }, + }, + methods: { + widgetTypeSelected() { + if (!this.isWidgetAvailable) { + this.$refs.deactivatedModal.show() + return + } + + this.$emit('widget-type-selected', this.widgetType.type) + }, + }, +} +</script> diff --git a/web-frontend/modules/dashboard/components/CreateWidgetModal.vue b/web-frontend/modules/dashboard/components/CreateWidgetModal.vue index 75fe6d5c4..310d4dac1 100644 --- a/web-frontend/modules/dashboard/components/CreateWidgetModal.vue +++ b/web-frontend/modules/dashboard/components/CreateWidgetModal.vue @@ -3,29 +3,26 @@ <h2 class="box__title"> {{ $t('createWidgetModal.title') }} </h2> - <div> - <a + <div class="create-widget-modal__cards"> + <CreateWidgetCard v-for="widgetType in widgetTypes" :key="widgetType.type" - class="create-widget-card" - @click="widgetTypeSelected(widgetType.type)" + :dashboard="dashboard" + :widget-type="widgetType" + @widget-type-selected="widgetTypeSelected" > - <div class="create-widget-card__img-container"> - <img :src="widgetType.createWidgetImage" /> - </div> - <div class="create-widget-card__name"> - {{ widgetType.name }} - </div> - </a> + </CreateWidgetCard> </div> </Modal> </template> <script> import modal from '@baserow/modules/core/mixins/modal' +import CreateWidgetCard from '@baserow/modules/dashboard/components/CreateWidgetCard' export default { name: 'CreateWidgetModal', + components: { CreateWidgetCard }, mixins: [modal], props: { dashboard: { diff --git a/web-frontend/modules/dashboard/widgetTypes.js b/web-frontend/modules/dashboard/widgetTypes.js index 54589ba45..3e1caefe4 100644 --- a/web-frontend/modules/dashboard/widgetTypes.js +++ b/web-frontend/modules/dashboard/widgetTypes.js @@ -36,6 +36,14 @@ export class WidgetType extends Registerable { isLoading(widget, data) { return false } + + isAvailable() { + return true + } + + getDeactivatedModal() { + return null + } } export class SummaryWidgetType extends WidgetType {