Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
be4cdd8
Add asset copy functionality with tabbed interface in asset creation …
joshuaunity May 22, 2026
f5aa38b
feat: Enhance asset copy tab with infinite scroll and loading indicators
joshuaunity May 22, 2026
d2c94fe
Update flexmeasures/ui/templates/assets/asset_new.html
joshuaunity May 25, 2026
609425b
feat: Add asset type filtering to asset API and update UI parameters
joshuaunity May 25, 2026
3336c0c
chore: add changelog entry
joshuaunity May 25, 2026
a1c3380
ref: make card title clickable
joshuaunity May 25, 2026
28329b9
feat: Set external_id to None in copy_asset to prevent unique constra…
joshuaunity May 25, 2026
4b472a4
chore: code linting
joshuaunity May 25, 2026
339f8ae
feat: Remove unused parentAssetId variable and related logic from ass…
joshuaunity May 25, 2026
967b378
Merge branch 'main' into feat/asset-create-copy-tab-ui-flow
joshuaunity May 29, 2026
5f4838f
feat: Update asset type handling and add AssetTypeIdField for better …
joshuaunity May 29, 2026
6573504
chore: code formatting
joshuaunity May 29, 2026
e5749e3
feat: Add parent asset ID handling for asset copy functionality
joshuaunity Jun 1, 2026
14b2902
feat: Set external_id to None when copying assets to avoid unique con…
joshuaunity Jun 1, 2026
b407e22
Update flexmeasures/ui/templates/assets/asset_new.html
joshuaunity Jun 2, 2026
5ce1008
fix: fixed issue were public assets are always added
joshuaunity Jun 2, 2026
5f3bdc2
feat: enhance asset copy UI with pagination and improved loading state
joshuaunity Jun 2, 2026
8a94c30
feat: update asset copy functionality to handle None values for accou…
joshuaunity Jun 12, 2026
26a042f
chore; set search input to search template keyword by default
joshuaunity Jun 12, 2026
e022ca4
Merge branch 'main' into feat/asset-create-copy-tab-ui-flow
nhoening Jul 1, 2026
75f242f
use all_accessible param to look up assets, show 15 per page
nhoening Jul 1, 2026
80b993f
add a doc section on how to create a child asset
nhoening Jul 1, 2026
25c75a1
no pre-fill of search term, let's do that in the next PR
nhoening Jul 1, 2026
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 documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ New features
* New ``GET /api/v3_0/sources`` endpoint to list accessible data sources and defined types, with ``only_latest=true`` by default to return only the most recent version per source [see `PR #2126 <https://www.github.com/FlexMeasures/flexmeasures/pull/2126>`_]
* Add support for filtering sensor data GET requests by ``source-type`` on ``/api/v3_0/sensors/<id>/data`` [see `PR #2127 <https://www.github.com/FlexMeasures/flexmeasures/pull/2127>`_]
* Making monitoring alerts more flexible: allow ``flexmeasures monitor`` alerts to target one or more user IDs or email addresses with ``--recipient``; ``flexmeasures monitor last-seen`` can now narrow monitored users to one or more accounts with ``--account`` or to client accounts with ``--consultancy`` [see `PR #2158 <https://www.github.com/FlexMeasures/flexmeasures/pull/2158>`_]
* Support for creating new assets by using another asset as a template from the UI. [see `PR #2195 <https://www.github.com/FlexMeasures/flexmeasures/pull/2195>`_]

Infrastructure / Support
----------------------
Expand Down
9 changes: 9 additions & 0 deletions flexmeasures/api/common/schemas/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ class AssetAPIQuerySchema(PaginationSchema):
example=False,
),
)
asset_type = fields.Int(
Comment thread
joshuaunity marked this conversation as resolved.
Outdated
data_key="asset_type",
required=False,
validate=validate.Range(min=1),
metadata=dict(
description="Filter assets by generic asset type ID.",
example=2,
),
)


class PublicAssetAPISchema(Schema):
Expand Down
3 changes: 3 additions & 0 deletions flexmeasures/api/common/utils/api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,9 @@ def copy_asset(
"Invalid copy target parent: cannot copy an asset to itself or any of its descendants."
)

# set external_id to None to avoid conflicts with unique constraint on (account_id, external_id)
asset.external_id = None
Comment thread
joshuaunity marked this conversation as resolved.
Outdated

copied_root, sensor_id_map = _copy_asset_subtree(
source_asset=asset,
destination_account_id=target_account_id,
Expand Down
6 changes: 6 additions & 0 deletions flexmeasures/api/v3_0/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ def index(
fields_in_response: list[str] | None,
all_accessible: bool,
include_public: bool,
asset_type: int | None = None,
account: Account | None = None,
root_asset: GenericAsset | None = None,
max_depth: int | None = None,
Expand All @@ -287,6 +288,7 @@ def index(
- The `account_id` query parameter can be used to list assets from any account (if the user is allowed to read them). Per default, the user's account is used.
- Alternatively, the `all_accessible` query parameter can be used to list assets from all accounts the current_user has read-access to, plus all public assets. Defaults to `false`.
- The `include_public` query parameter can be used to include public assets in the response. Defaults to `false`.
- The `asset_type` query parameter can be used to filter by generic asset type ID.
- The `root` query parameter can be used to list only descendants of a given root asset (including the root itself).
- The `depth` query parameter can be used to search only a max number of descendant generations from the root.

Expand Down Expand Up @@ -363,6 +365,10 @@ def index(
filter_statement = GenericAsset.account_id.in_(account_ids)
if include_public:
filter_statement = filter_statement | GenericAsset.account_id.is_(None)
if asset_type is not None:
filter_statement = filter_statement & (
GenericAsset.generic_asset_type_id == asset_type
)

query = query_assets_by_search_terms(
search_terms=filter,
Expand Down
29 changes: 29 additions & 0 deletions flexmeasures/api/v3_0/tests/test_assets_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ def test_get_assets(
assert turbine["account_id"] == setup_accounts["Supplier"].id


@pytest.mark.parametrize("requesting_user", ["test_admin_user@seita.nl"], indirect=True)
def test_get_assets_filtered_by_asset_type(client, setup_accounts, requesting_user):
supplier_account = setup_accounts["Supplier"]
supplier_account_id = supplier_account.id
supplier_assets = supplier_account.generic_assets

requested_type_id = supplier_assets[0].generic_asset_type_id
expected_assets = [
asset
for asset in supplier_assets
if asset.generic_asset_type_id == requested_type_id
]

response = client.get(
url_for("AssetAPI:index"),
query_string={
"account_id": supplier_account_id,
"asset_type": requested_type_id,
},
)

assert response.status_code == 200
assert len(response.json) == len(expected_assets)
assert all(
asset["generic_asset_type"]["id"] == requested_type_id
for asset in response.json
)


@pytest.mark.parametrize(
"requesting_user, sort_by, sort_dir, expected_name_of_first_sensor",
[
Expand Down
Loading
Loading