diff --git a/src/wuttafarm/db/alembic/versions/dd6351e69233_add_generic_log_base.py b/src/wuttafarm/db/alembic/versions/dd6351e69233_add_generic_log_base.py
new file mode 100644
index 0000000..0b82da9
--- /dev/null
+++ b/src/wuttafarm/db/alembic/versions/dd6351e69233_add_generic_log_base.py
@@ -0,0 +1,206 @@
+"""add generic log base
+
+Revision ID: dd6351e69233
+Revises: b8cd4a8f981f
+Create Date: 2026-02-18 12:09:05.200134
+
+"""
+
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+import wuttjamaican.db.util
+from sqlalchemy.dialects import postgresql
+
+# revision identifiers, used by Alembic.
+revision: str = "dd6351e69233"
+down_revision: Union[str, None] = "b8cd4a8f981f"
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+
+ # log
+ op.create_table(
+ "log",
+ sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
+ sa.Column("log_type", sa.String(length=100), nullable=False),
+ sa.Column("message", sa.String(length=255), nullable=False),
+ sa.Column("timestamp", sa.DateTime(), nullable=False),
+ sa.Column("status", sa.String(length=20), nullable=False),
+ sa.Column("notes", sa.Text(), nullable=True),
+ sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True),
+ sa.Column("drupal_id", sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(
+ ["log_type"], ["log_type.drupal_id"], name=op.f("fk_log_log_type_log_type")
+ ),
+ sa.PrimaryKeyConstraint("uuid", name=op.f("pk_log")),
+ sa.UniqueConstraint("drupal_id", name=op.f("uq_log_drupal_id")),
+ sa.UniqueConstraint("farmos_uuid", name=op.f("uq_log_farmos_uuid")),
+ )
+ op.create_table(
+ "log_version",
+ sa.Column(
+ "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False
+ ),
+ sa.Column(
+ "log_type", sa.String(length=100), autoincrement=False, nullable=True
+ ),
+ sa.Column("message", sa.String(length=255), autoincrement=False, nullable=True),
+ sa.Column("timestamp", sa.DateTime(), autoincrement=False, nullable=True),
+ sa.Column("status", sa.String(length=20), autoincrement=False, nullable=True),
+ sa.Column("notes", sa.Text(), autoincrement=False, nullable=True),
+ sa.Column(
+ "farmos_uuid",
+ wuttjamaican.db.util.UUID(),
+ autoincrement=False,
+ nullable=True,
+ ),
+ sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True),
+ sa.Column(
+ "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False
+ ),
+ sa.Column("end_transaction_id", sa.BigInteger(), nullable=True),
+ sa.Column("operation_type", sa.SmallInteger(), nullable=False),
+ sa.PrimaryKeyConstraint("uuid", "transaction_id", name=op.f("pk_log_version")),
+ )
+ op.create_index(
+ op.f("ix_log_version_end_transaction_id"),
+ "log_version",
+ ["end_transaction_id"],
+ unique=False,
+ )
+ op.create_index(
+ op.f("ix_log_version_operation_type"),
+ "log_version",
+ ["operation_type"],
+ unique=False,
+ )
+ op.create_index(
+ "ix_log_version_pk_transaction_id",
+ "log_version",
+ ["uuid", sa.literal_column("transaction_id DESC")],
+ unique=False,
+ )
+ op.create_index(
+ "ix_log_version_pk_validity",
+ "log_version",
+ ["uuid", "transaction_id", "end_transaction_id"],
+ unique=False,
+ )
+ op.create_index(
+ op.f("ix_log_version_transaction_id"),
+ "log_version",
+ ["transaction_id"],
+ unique=False,
+ )
+
+ # log_activity
+ op.drop_column("log_activity_version", "status")
+ op.drop_column("log_activity_version", "farmos_uuid")
+ op.drop_column("log_activity_version", "timestamp")
+ op.drop_column("log_activity_version", "message")
+ op.drop_column("log_activity_version", "drupal_id")
+ op.drop_column("log_activity_version", "notes")
+ op.drop_constraint(
+ op.f("uq_log_activity_drupal_id"), "log_activity", type_="unique"
+ )
+ op.drop_constraint(
+ op.f("uq_log_activity_farmos_uuid"), "log_activity", type_="unique"
+ )
+ op.create_foreign_key(
+ op.f("fk_log_activity_uuid_log"), "log_activity", "log", ["uuid"], ["uuid"]
+ )
+ op.drop_column("log_activity", "status")
+ op.drop_column("log_activity", "farmos_uuid")
+ op.drop_column("log_activity", "timestamp")
+ op.drop_column("log_activity", "message")
+ op.drop_column("log_activity", "drupal_id")
+ op.drop_column("log_activity", "notes")
+
+
+def downgrade() -> None:
+
+ # log_activity
+ op.add_column(
+ "log_activity",
+ sa.Column("notes", sa.TEXT(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity",
+ sa.Column("drupal_id", sa.INTEGER(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity",
+ sa.Column(
+ "message", sa.VARCHAR(length=255), autoincrement=False, nullable=False
+ ),
+ )
+ op.add_column(
+ "log_activity",
+ sa.Column(
+ "timestamp", postgresql.TIMESTAMP(), autoincrement=False, nullable=False
+ ),
+ )
+ op.add_column(
+ "log_activity",
+ sa.Column("farmos_uuid", sa.UUID(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity",
+ sa.Column("status", sa.VARCHAR(length=20), autoincrement=False, nullable=False),
+ )
+ op.drop_constraint(
+ op.f("fk_log_activity_uuid_log"), "log_activity", type_="foreignkey"
+ )
+ op.create_unique_constraint(
+ op.f("uq_log_activity_farmos_uuid"),
+ "log_activity",
+ ["farmos_uuid"],
+ postgresql_nulls_not_distinct=False,
+ )
+ op.create_unique_constraint(
+ op.f("uq_log_activity_drupal_id"),
+ "log_activity",
+ ["drupal_id"],
+ postgresql_nulls_not_distinct=False,
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column("notes", sa.TEXT(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column("drupal_id", sa.INTEGER(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column(
+ "message", sa.VARCHAR(length=255), autoincrement=False, nullable=True
+ ),
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column(
+ "timestamp", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
+ ),
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column("farmos_uuid", sa.UUID(), autoincrement=False, nullable=True),
+ )
+ op.add_column(
+ "log_activity_version",
+ sa.Column("status", sa.VARCHAR(length=20), autoincrement=False, nullable=True),
+ )
+
+ # log
+ op.drop_index(op.f("ix_log_version_transaction_id"), table_name="log_version")
+ op.drop_index("ix_log_version_pk_validity", table_name="log_version")
+ op.drop_index("ix_log_version_pk_transaction_id", table_name="log_version")
+ op.drop_index(op.f("ix_log_version_operation_type"), table_name="log_version")
+ op.drop_index(op.f("ix_log_version_end_transaction_id"), table_name="log_version")
+ op.drop_table("log_version")
+ op.drop_table("log")
diff --git a/src/wuttafarm/db/model/__init__.py b/src/wuttafarm/db/model/__init__.py
index 277a92c..978ed5d 100644
--- a/src/wuttafarm/db/model/__init__.py
+++ b/src/wuttafarm/db/model/__init__.py
@@ -35,4 +35,5 @@ from .asset_land import LandType, LandAsset
from .asset_structure import StructureType, StructureAsset
from .asset_animal import AnimalType, AnimalAsset
from .asset_group import GroupAsset
-from .logs import LogType, ActivityLog
+from .log import LogType, Log
+from .log_activity import ActivityLog
diff --git a/src/wuttafarm/db/model/logs.py b/src/wuttafarm/db/model/log.py
similarity index 76%
rename from src/wuttafarm/db/model/logs.py
rename to src/wuttafarm/db/model/log.py
index 76f7715..14afe3e 100644
--- a/src/wuttafarm/db/model/logs.py
+++ b/src/wuttafarm/db/model/log.py
@@ -20,11 +20,12 @@
#
################################################################################
"""
-Model definition for Log Types
+Model definition for Logs
"""
import sqlalchemy as sa
from sqlalchemy import orm
+from sqlalchemy.ext.declarative import declared_attr
from wuttjamaican.db import model
@@ -82,20 +83,26 @@ class LogType(model.Base):
return self.name or ""
-class ActivityLog(model.Base):
+class Log(model.Base):
"""
- Represents an activity log from farmOS
+ Represents a base log record from farmOS
"""
- __tablename__ = "log_activity"
+ __tablename__ = "log"
__versioned__ = {}
__wutta_hint__ = {
- "model_title": "Activity Log",
- "model_title_plural": "Activity Logs",
+ "model_title": "Log",
+ "model_title_plural": "Logs",
}
uuid = model.uuid_column()
+ log_type = sa.Column(
+ sa.String(length=100),
+ sa.ForeignKey("log_type.drupal_id"),
+ nullable=False,
+ )
+
message = sa.Column(
sa.String(length=255),
nullable=False,
@@ -148,3 +155,25 @@ class ActivityLog(model.Base):
def __str__(self):
return self.message or ""
+
+
+class LogMixin:
+
+ uuid = model.uuid_fk_column("log.uuid", nullable=False, primary_key=True)
+
+ @declared_attr
+ def log(cls):
+ return orm.relationship(Log)
+
+ def __str__(self):
+ return self.message or ""
+
+
+def add_log_proxies(subclass):
+ Log.make_proxy(subclass, "log", "farmos_uuid")
+ Log.make_proxy(subclass, "log", "drupal_id")
+ Log.make_proxy(subclass, "log", "log_type")
+ Log.make_proxy(subclass, "log", "message")
+ Log.make_proxy(subclass, "log", "timestamp")
+ Log.make_proxy(subclass, "log", "status")
+ Log.make_proxy(subclass, "log", "notes")
diff --git a/src/wuttafarm/db/model/log_activity.py b/src/wuttafarm/db/model/log_activity.py
new file mode 100644
index 0000000..bbf8154
--- /dev/null
+++ b/src/wuttafarm/db/model/log_activity.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# WuttaFarm --Web app to integrate with and extend farmOS
+# Copyright © 2026 Lance Edgar
+#
+# This file is part of WuttaFarm.
+#
+# WuttaFarm is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# WuttaFarm. If not, see .
+#
+################################################################################
+"""
+Model definition for Activity Logs
+"""
+
+from wuttjamaican.db import model
+
+from wuttafarm.db.model.log import LogMixin, add_log_proxies
+
+
+class ActivityLog(LogMixin, model.Base):
+ """
+ Represents an activity log from farmOS
+ """
+
+ __tablename__ = "log_activity"
+ __versioned__ = {}
+ __wutta_hint__ = {
+ "model_title": "Activity Log",
+ "model_title_plural": "Activity Logs",
+ "farmos_log_type": "activity",
+ }
+
+
+add_log_proxies(ActivityLog)
diff --git a/src/wuttafarm/importing/farmos.py b/src/wuttafarm/importing/farmos.py
index b07d06d..e421f26 100644
--- a/src/wuttafarm/importing/farmos.py
+++ b/src/wuttafarm/importing/farmos.py
@@ -139,43 +139,6 @@ class FromFarmOS(Importer):
return self.app.make_utc(dt)
-class ActivityLogImporter(FromFarmOS, ToWutta):
- """
- farmOS API → WuttaFarm importer for Activity Logs
- """
-
- model_class = model.ActivityLog
-
- supported_fields = [
- "farmos_uuid",
- "drupal_id",
- "message",
- "timestamp",
- "notes",
- "status",
- ]
-
- def get_source_objects(self):
- """ """
- logs = self.farmos_client.log.get("activity")
- return logs["data"]
-
- def normalize_source_object(self, log):
- """ """
-
- if notes := log["attributes"]["notes"]:
- notes = notes["value"]
-
- return {
- "farmos_uuid": UUID(log["id"]),
- "drupal_id": log["attributes"]["drupal_internal__id"],
- "message": log["attributes"]["name"],
- "timestamp": self.normalize_datetime(log["attributes"]["timestamp"]),
- "notes": notes,
- "status": log["attributes"]["status"],
- }
-
-
class AssetImporterBase(FromFarmOS, ToWutta):
"""
Base class for farmOS API → WuttaFarm asset importers
@@ -320,6 +283,71 @@ class AssetImporterBase(FromFarmOS, ToWutta):
return asset
+class LogImporterBase(FromFarmOS, ToWutta):
+ """
+ Base class for farmOS API → WuttaFarm log importers
+ """
+
+ def get_farmos_log_type(self):
+ return self.model_class.__wutta_hint__["farmos_log_type"]
+
+ def get_simple_fields(self):
+ """ """
+ fields = list(super().get_simple_fields())
+ # nb. must explicitly declare proxy fields
+ fields.extend(
+ [
+ "farmos_uuid",
+ "drupal_id",
+ "log_type",
+ "message",
+ "timestamp",
+ "notes",
+ "status",
+ ]
+ )
+ return fields
+
+ def get_source_objects(self):
+ """ """
+ log_type = self.get_farmos_log_type()
+ result = self.farmos_client.log.get(log_type)
+ return result["data"]
+
+ def normalize_source_object(self, log):
+ """ """
+ if notes := log["attributes"]["notes"]:
+ notes = notes["value"]
+
+ return {
+ "farmos_uuid": UUID(log["id"]),
+ "drupal_id": log["attributes"]["drupal_internal__id"],
+ "log_type": self.get_farmos_log_type(),
+ "message": log["attributes"]["name"],
+ "timestamp": self.normalize_datetime(log["attributes"]["timestamp"]),
+ "notes": notes,
+ "status": log["attributes"]["status"],
+ }
+
+
+class ActivityLogImporter(LogImporterBase):
+ """
+ farmOS API → WuttaFarm importer for Activity Logs
+ """
+
+ model_class = model.ActivityLog
+
+ supported_fields = [
+ "farmos_uuid",
+ "drupal_id",
+ "log_type",
+ "message",
+ "timestamp",
+ "notes",
+ "status",
+ ]
+
+
class AnimalAssetImporter(AssetImporterBase):
"""
farmOS API → WuttaFarm importer for Animals
diff --git a/src/wuttafarm/web/views/__init__.py b/src/wuttafarm/web/views/__init__.py
index e44c16e..fe42703 100644
--- a/src/wuttafarm/web/views/__init__.py
+++ b/src/wuttafarm/web/views/__init__.py
@@ -47,7 +47,7 @@ def includeme(config):
config.include("wuttafarm.web.views.structures")
config.include("wuttafarm.web.views.animals")
config.include("wuttafarm.web.views.groups")
- config.include("wuttafarm.web.views.log_types")
+ config.include("wuttafarm.web.views.logs")
config.include("wuttafarm.web.views.logs_activity")
# views for farmOS
diff --git a/src/wuttafarm/web/views/log_types.py b/src/wuttafarm/web/views/log_types.py
deleted file mode 100644
index 13ea35f..0000000
--- a/src/wuttafarm/web/views/log_types.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# -*- coding: utf-8; -*-
-################################################################################
-#
-# WuttaFarm --Web app to integrate with and extend farmOS
-# Copyright © 2026 Lance Edgar
-#
-# This file is part of WuttaFarm.
-#
-# WuttaFarm is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation, either version 3 of the License, or (at your option) any later
-# version.
-#
-# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# WuttaFarm. If not, see .
-#
-################################################################################
-"""
-Master view for Log Types
-"""
-
-from wuttafarm.db.model.logs import LogType
-from wuttafarm.web.views import WuttaFarmMasterView
-
-
-class LogTypeView(WuttaFarmMasterView):
- """
- Master view for Log Types
- """
-
- model_class = LogType
- route_prefix = "log_types"
- url_prefix = "/log-types"
-
- grid_columns = [
- "name",
- "description",
- ]
-
- sort_defaults = "name"
-
- filter_defaults = {
- "name": {"active": True, "verb": "contains"},
- }
-
- form_fields = [
- "name",
- "description",
- "farmos_uuid",
- "drupal_id",
- ]
-
- def configure_grid(self, grid):
- g = grid
- super().configure_grid(g)
-
- # name
- g.set_link("name")
-
- def get_xref_buttons(self, log_type):
- buttons = super().get_xref_buttons(log_type)
-
- if log_type.farmos_uuid:
- buttons.append(
- self.make_button(
- "View farmOS record",
- primary=True,
- url=self.request.route_url(
- "farmos_log_types.view", uuid=log_type.farmos_uuid
- ),
- icon_left="eye",
- )
- )
-
- return buttons
-
-
-def defaults(config, **kwargs):
- base = globals()
-
- LogTypeView = kwargs.get("LogTypeView", base["LogTypeView"])
- LogTypeView.defaults(config)
-
-
-def includeme(config):
- defaults(config)
diff --git a/src/wuttafarm/web/views/logs.py b/src/wuttafarm/web/views/logs.py
new file mode 100644
index 0000000..fc05613
--- /dev/null
+++ b/src/wuttafarm/web/views/logs.py
@@ -0,0 +1,223 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# WuttaFarm --Web app to integrate with and extend farmOS
+# Copyright © 2026 Lance Edgar
+#
+# This file is part of WuttaFarm.
+#
+# WuttaFarm is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# WuttaFarm. If not, see .
+#
+################################################################################
+"""
+Base views for Logs
+"""
+
+from collections import OrderedDict
+
+from wuttaweb.forms.schema import WuttaDictEnum
+from wuttaweb.db import Session
+from wuttaweb.forms.widgets import WuttaDateTimeWidget
+
+from wuttafarm.web.views import WuttaFarmMasterView
+from wuttafarm.db.model import LogType
+
+
+def get_log_type_enum(config):
+ app = config.get_app()
+ model = app.model
+ session = Session()
+ log_types = OrderedDict()
+ query = session.query(model.LogType).order_by(model.LogType.name)
+ for log_type in query:
+ log_types[log_type.drupal_id] = log_type.name
+ return log_types
+
+
+class LogTypeView(WuttaFarmMasterView):
+ """
+ Master view for Log Types
+ """
+
+ model_class = LogType
+ route_prefix = "log_types"
+ url_prefix = "/log-types"
+
+ grid_columns = [
+ "name",
+ "description",
+ ]
+
+ sort_defaults = "name"
+
+ filter_defaults = {
+ "name": {"active": True, "verb": "contains"},
+ }
+
+ form_fields = [
+ "name",
+ "description",
+ "farmos_uuid",
+ "drupal_id",
+ ]
+
+ def configure_grid(self, grid):
+ g = grid
+ super().configure_grid(g)
+
+ # name
+ g.set_link("name")
+
+ def get_xref_buttons(self, log_type):
+ buttons = super().get_xref_buttons(log_type)
+
+ if log_type.farmos_uuid:
+ buttons.append(
+ self.make_button(
+ "View farmOS record",
+ primary=True,
+ url=self.request.route_url(
+ "farmos_log_types.view", uuid=log_type.farmos_uuid
+ ),
+ icon_left="eye",
+ )
+ )
+
+ return buttons
+
+
+class LogMasterView(WuttaFarmMasterView):
+ """
+ Base class for Asset master views
+ """
+
+ grid_columns = [
+ "status",
+ "drupal_id",
+ "timestamp",
+ "message",
+ "assets",
+ "location",
+ "quantity",
+ "is_group_assignment",
+ ]
+
+ sort_defaults = ("timestamp", "desc")
+
+ filter_defaults = {
+ "message": {"active": True, "verb": "contains"},
+ }
+
+ form_fields = [
+ "message",
+ "timestamp",
+ "assets",
+ "location",
+ "quantity",
+ "notes",
+ "status",
+ "log_type",
+ "owners",
+ "is_group_assignment",
+ "farmos_uuid",
+ "drupal_id",
+ ]
+
+ def get_query(self, session=None):
+ """ """
+ model = self.app.model
+ model_class = self.get_model_class()
+ session = session or self.Session()
+ return session.query(model_class).join(model.Log)
+
+ def configure_grid(self, grid):
+ g = grid
+ super().configure_grid(g)
+ model = self.app.model
+
+ # status
+ g.set_sorter("status", model.Log.status)
+ g.set_filter("status", model.Log.status)
+
+ # drupal_id
+ g.set_label("drupal_id", "ID", column_only=True)
+ g.set_sorter("drupal_id", model.Log.drupal_id)
+ g.set_filter("drupal_id", model.Log.drupal_id)
+
+ # timestamp
+ g.set_renderer("timestamp", "date")
+ g.set_link("timestamp")
+ g.set_sorter("timestamp", model.Log.timestamp)
+ g.set_filter("timestamp", model.Log.timestamp)
+
+ # message
+ g.set_link("message")
+ g.set_sorter("message", model.Log.message)
+ g.set_filter("message", model.Log.message)
+
+ def configure_form(self, form):
+ f = form
+ super().configure_form(f)
+
+ # timestamp
+ # TODO: the widget should be automatic (assn proxy field)
+ f.set_widget("timestamp", WuttaDateTimeWidget(self.request))
+
+ # log_type
+ if self.creating:
+ f.remove("log_type")
+ else:
+ f.set_node(
+ "log_type",
+ WuttaDictEnum(self.request, get_log_type_enum(self.config)),
+ )
+ f.set_readonly("log_type")
+
+ # notes
+ f.set_widget("notes", "notes")
+
+ def get_farmos_url(self, log):
+ return self.app.get_farmos_url(f"/log/{log.drupal_id}")
+
+ def get_xref_buttons(self, log):
+ buttons = super().get_xref_buttons(log)
+
+ if log.farmos_uuid:
+
+ # TODO
+ route = None
+ if log.log_type == "activity":
+ route = "farmos_logs_activity.view"
+
+ if route:
+ buttons.append(
+ self.make_button(
+ "View farmOS record",
+ primary=True,
+ url=self.request.route_url(route, uuid=log.farmos_uuid),
+ icon_left="eye",
+ )
+ )
+
+ return buttons
+
+
+def defaults(config, **kwargs):
+ base = globals()
+
+ LogTypeView = kwargs.get("LogTypeView", base["LogTypeView"])
+ LogTypeView.defaults(config)
+
+
+def includeme(config):
+ defaults(config)
diff --git a/src/wuttafarm/web/views/logs_activity.py b/src/wuttafarm/web/views/logs_activity.py
index a2b2154..d4333f5 100644
--- a/src/wuttafarm/web/views/logs_activity.py
+++ b/src/wuttafarm/web/views/logs_activity.py
@@ -23,11 +23,11 @@
Master view for Activity Logs
"""
-from wuttafarm.db.model.logs import ActivityLog
-from wuttafarm.web.views import WuttaFarmMasterView
+from wuttafarm.web.views.logs import LogMasterView
+from wuttafarm.db.model import ActivityLog
-class ActivityLogView(WuttaFarmMasterView):
+class ActivityLogView(LogMasterView):
"""
Master view for Activity Logs
"""
@@ -38,61 +38,6 @@ class ActivityLogView(WuttaFarmMasterView):
farmos_refurl_path = "/logs/activity"
- grid_columns = [
- "message",
- "timestamp",
- "status",
- ]
-
- sort_defaults = ("timestamp", "desc")
-
- filter_defaults = {
- "message": {"active": True, "verb": "contains"},
- }
-
- form_fields = [
- "message",
- "timestamp",
- "status",
- "notes",
- "farmos_uuid",
- "drupal_id",
- ]
-
- def configure_grid(self, grid):
- g = grid
- super().configure_grid(g)
-
- # message
- g.set_link("message")
-
- def configure_form(self, form):
- f = form
- super().configure_form(f)
-
- # notes
- f.set_widget("notes", "notes")
-
- def get_farmos_url(self, log):
- return self.app.get_farmos_url(f"/log/{log.drupal_id}")
-
- def get_xref_buttons(self, log):
- buttons = super().get_xref_buttons(log)
-
- if log.farmos_uuid:
- buttons.append(
- self.make_button(
- "View farmOS record",
- primary=True,
- url=self.request.route_url(
- "farmos_logs_activity.view", uuid=log.farmos_uuid
- ),
- icon_left="eye",
- )
- )
-
- return buttons
-
def defaults(config, **kwargs):
base = globals()