Cant install plugins in instance

Are you using our SaaS platform (Baserow.io) or self-hosting Baserow?

Self-hosted

If you are self-hosting, what version of Baserow are you running?

Im using 1.33.2

If you are self-hosting, which installation method do you use to run Baserow?

Docker version 28.2.2, build e6534b4

What are the exact steps to reproduce this issue?

I followed the tutorial steps on how to setup a plugin. The first and easiest one was successful, the integer_field plugin or the application_type were not. Im not sure why, because I followed the tutorial steps exactly as described. Furthermore I wanted to run all the plugins in one container so that they are in one instance. What I noticed in the logs was the message that a backend app was found in the first plugin. No was found in the other 2. What could be a reason for that? I would be very happy if anybody could help me.

Hi!

Can you share more details on your dev environment?

  • can you tell more how do you run the container (docker invocation, compose file if used, settings/env vars used)?
  • can you show logs from the container?
  • if possible, can you share the code of your plugins?
  • can you list contents of /baserow/plugins/ directory in the container?
  • can you show output of baserow list-plugins command (Plugin Installation)?

Please, note that 3rd party plugin development is in the early stage - the documentation may be not accurate, and there may be some undocumented pathways regarding development.

Thank you for your reply, yes of course.

docker run -p 80:80 -v baserow_data:/baserow/data my-customized-baserow:1.33.2 

is the command for running it.

After the start I can see this output

The Dockerfile looks like this

FROM baserow/baserow:1.33.2

COPY ./my-baserow-plugin/ /baserow/data/plugins/my_baserow_plugin/
COPY ./app-type-plugin/ /baserow/data/plugins/app_type_plugin/
COPY ./integer-field-plugin/ /baserow/data/plugins/integer_field_plugin/
RUN /baserow/plugins/install_plugin.sh --folder /baserow/data/plugins/my_baserow_plugin
RUN /baserow/plugins/install_plugin.sh --folder /baserow/data/plugins/app_type_plugin
RUN /baserow/plugins/install_plugin.sh --folder /baserow/data/plugins/integer_field_plugin

The output from baserow/plugins directory are only the shell scripts
and list plugins shows all plugins which I have inside my Dockerfile.

Im gonna show you just one plugin now because the message will be too long.

baserow/integer-field-plugin/plugins/integer_field_plugin/backend/src/integer_field_plugin

apps.py

from django.apps import AppConfig

from baserow.core.registries import plugin_registry
from baserow.contrib.database.fields.registries import field_type_registry

class IntegerFieldConfig(AppConfig):
    name = "integer_field_plugin"

    def ready(self):
        from .plugins import IntegerFieldPlugin
        from .field_types import IntegerFieldType

        plugin_registry.register(IntegerFieldPlugin())
        field_type_registry.register(IntegerFieldType())

field_types

from django.db import models
from django.core.exceptions import ValidationError

from rest_framework import serializers

from baserow.contrib.database.fields.registries import FieldType

from .models import IntegerField


class IntegerFieldType(FieldType):
    type = 'integer'
    model_class = IntegerField
    allowed_fields = ['integer_negative']
    serializer_field_names = ['integer_negative']

    def prepare_value_for_db(self, instance, value):
        if value and not instance.integer_negative and value < 0:
            raise ValidationError(f'The value for field {instance.id} cannot be '
                                  f'negative.')
        return value

    def get_serializer_field(self, instance, **kwargs):
        return serializers.IntegerField(required=False, allow_null=True)

    def get_model_field(self, instance, **kwargs):
        return models.IntegerField(null=True, blank=True)

models.py

from django.db import models

from baserow.contrib.database.fields.models import Field


class IntegerField(Field):
    integer_negative = models.BooleanField(default=False)

plugins.py

from loguru import logger
from baserow.core.registries import Plugin
from django.urls import path, include

from .api import urls as api_urls


class IntegerFieldPlugin(Plugin):
    type = "integer_field_plugin"

    def get_api_urls(self):
        return [
            path(
                "integer_field_plugin/",
                include(api_urls, namespace=self.type),
            ),
        ]

baserow/integer-field-plugin/plugins/integer_field_plugin/web-frontend/plugin.js

import { PluginNamePlugin } from "@integer-field-plugin/plugins";
import { IntegerFieldType } from "@integer-field-plugin/fieldTypes";

export default (context) => {
    const { app } = context;
    app.$registry.register("plugin", new PluginNamePlugin(context));
    app.$registry.register("field", new IntegerFieldType(context));
};

fieldTypes.js

import { FieldType } from "@baserow/modules/database/fieldTypes";

import SubFormIntegerField from "@integer-field-type/components/SubFormIntegerField";
import GridViewIntegerField from "@integer-field-type/components/GridViewIntegerField";
import RowEditIntegerField from "@integer-field-type/components/RowEditIntegerField";

export class IntegerFieldType extends FieldType {
    static getType() {
        return "integer";
    }

    getIconClass() {
        return "iconoir-numbered-list-left";
    }

    getName() {
        return "Integer";
    }

    getFormComponent() {
        return SubFormIntegerField;
    }

    getGridViewFieldComponent() {
        return GridViewIntegerField;
    }

    getRowEditFieldComponent(field) {
        return RowEditIntegerField;
    }
}

/modules/components

GridViewIntegerField.vue

<template>
    <div class="grid-view__cell" :class="{ active: selected }">
        <div>Hello World</div>
    </div>
</template>

<script>
import gridField from "@baserow/modules/database/mixins/gridField";

export default {
    mixins: [gridField],
};
</script>

RowEditIntegerField.vue

<template>
    <div class="control__elements">Hello World</div>
</template>

<script>
import rowEditField from "@baserow/modules/database/mixins/rowEditField";

export default {
    mixins: [rowEditField],
};
</script>

SubFormIntegerField.vue

template>
    <div>
        <div class="control">
            <div class="control__elements">
                <Checkbox v-model="values.integer_negative"
                    >Allow negative</Checkbox
                >
            </div>
        </div>
    </div>
</template>

<script>
import form from "@baserow/modules/core/mixins/form";

export default {
    name: "SubFormIntegerField",
    mixins: [form],
    data() {
        return {
            allowedValues: ["integer_negative"],
            values: { integer_negative: false },
        };
    },
    methods: {
        isFormValid() {
            return true;
        },
    },
};
</script>

Can you show backend dirs for plugins that didn’t install properly? I’m interested in:

  • the structure of directories
  • contents of setup.py

Yes, here an example of the application type plugin from the tutorial.

Also the setup.py from this plugin

#!/usr/bin/env python
import os

from setuptools import find_packages, setup

PROJECT_DIR = os.path.dirname(__file__)
REQUIREMENTS_DIR = os.path.join(PROJECT_DIR, "requirements")
VERSION = "1.0.0"


def get_requirements(env):
    with open(os.path.join(REQUIREMENTS_DIR, f"{env}.txt")) as fp:
        return [
            x.strip()
            for x in fp.read().split("\n")
            if not x.strip().startswith("#") and not x.strip().startswith("-")
        ]


install_requires = get_requirements("base")

setup(
    name="app-type-plugin",
    version=VERSION,
    url="TODO",
    author="TODO",
    author_email="TODO",
    license="TODO",
    description="TODO",
    long_description="TODO",
    platforms=["linux"],
    package_dir={"": "src"},
    packages=find_packages("src"),
    include_package_data=True,
    install_requires=install_requires
)

Also to mention that the setup.py is identical to the setup.py from the working plugin, just the name of course differs.

Can you install manually to the venv in the container (pip install path/to/repo/) ?

yes, I can manually install stuff inside my container

Hi!

Can you also show logs from docker build?