From 89b9ce852ab919928bb71d1ac558db8c35e8d9d6 Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Tue, 12 May 2026 07:15:56 +0000 Subject: [PATCH 1/6] feat(gooddata-sdk): [AUTO] Add DeclarativeIpAllowlistPolicy schema to declarative org config --- .../gooddata-sdk/src/gooddata_sdk/__init__.py | 3 ++ .../layout/ip_allowlist_policy.py | 22 ++++++++++++ .../catalog/organization/service.py | 33 +++++++++++++++++ .../catalog/test_catalog_organization.py | 35 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py diff --git a/packages/gooddata-sdk/src/gooddata_sdk/__init__.py b/packages/gooddata-sdk/src/gooddata_sdk/__init__.py index 91f87c918..e3cc5d4a1 100644 --- a/packages/gooddata-sdk/src/gooddata_sdk/__init__.py +++ b/packages/gooddata-sdk/src/gooddata_sdk/__init__.py @@ -133,6 +133,9 @@ from gooddata_sdk.catalog.organization.layout.export_template import ( CatalogDeclarativeExportTemplate, ) +from gooddata_sdk.catalog.organization.layout.ip_allowlist_policy import ( + CatalogDeclarativeIpAllowlistPolicy, +) from gooddata_sdk.catalog.organization.layout.notification_channel import ( CatalogDeclarativeNotificationChannel, CatalogWebhook, diff --git a/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py b/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py new file mode 100644 index 000000000..74f0407d5 --- /dev/null +++ b/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py @@ -0,0 +1,22 @@ +# (C) 2025 GoodData Corporation +from __future__ import annotations + +import builtins + +from attrs import define, field +from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy + +from gooddata_sdk.catalog.base import Base +from gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier + + +@define(kw_only=True) +class CatalogDeclarativeIpAllowlistPolicy(Base): + id: str + allowed_sources: list[str] = field(factory=list) + user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list) + users: list[CatalogUserIdentifier] = field(factory=list) + + @staticmethod + def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]: + return DeclarativeIpAllowlistPolicy diff --git a/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py b/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py index c05de1350..b79d3c9a6 100644 --- a/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py +++ b/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py @@ -31,6 +31,7 @@ ) from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting from gooddata_sdk.catalog.organization.layout.identity_provider import CatalogDeclarativeIdentityProvider +from gooddata_sdk.catalog.organization.layout.ip_allowlist_policy import CatalogDeclarativeIpAllowlistPolicy from gooddata_sdk.catalog.organization.layout.notification_channel import CatalogDeclarativeNotificationChannel from gooddata_sdk.client import GoodDataApiClient from gooddata_sdk.utils import load_all_entities, load_all_entities_dict @@ -742,3 +743,35 @@ def switch_active_identity_provider(self, identity_provider_id: str) -> None: ) except Exception as e: raise ValueError(f"Error switching active identity provider: {str(e)}") + + def get_declarative_ip_allowlist_policies(self) -> list[CatalogDeclarativeIpAllowlistPolicy]: + """Get all declarative IP allowlist policies for the current organization. + + IP allowlist policies are returned as part of the full organization layout. + + Returns: + list[CatalogDeclarativeIpAllowlistPolicy]: + List of declarative IP allowlist policies. + """ + org_layout = self._layout_api.get_organization_layout(_check_return_type=False) + policies = getattr(org_layout, "ip_allowlist_policies", None) or [] + return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies] + + def put_declarative_ip_allowlist_policies( + self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy] + ) -> None: + """Put declarative IP allowlist policies for the current organization. + + Reads the full organization layout, replaces the ip_allowlist_policies field, + and writes the full layout back. All other organization settings are preserved. + + Args: + ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]): + List of declarative IP allowlist policies to set. + + Returns: + None + """ + org_layout = self._layout_api.get_organization_layout(_check_return_type=False) + org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies] + self._layout_api.set_organization_layout(org_layout, _check_return_type=False) diff --git a/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py b/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py index 53e88c566..119eb8f92 100644 --- a/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py +++ b/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py @@ -6,6 +6,7 @@ from gooddata_api_client.exceptions import NotFoundException from gooddata_sdk import ( CatalogCspDirective, + CatalogDeclarativeIpAllowlistPolicy, CatalogDeclarativeNotificationChannel, CatalogJwk, CatalogOrganization, @@ -14,6 +15,7 @@ CatalogWebhook, GoodDataSdk, ) +from gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier from tests_support.vcrpy_utils import get_vcr from .conftest import safe_delete @@ -563,3 +565,36 @@ def test_layout_notification_channels(test_config, snapshot_notification_channel # sdk.catalog_organization.put_declarative_identity_providers([]) # idps = sdk.catalog_organization.get_declarative_identity_providers() # assert len(idps) == 0 + + +@gd_vcr.use_cassette(str(_fixtures_dir / "layout_ip_allowlist_policies.yaml")) +def test_layout_ip_allowlist_policies(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies() + + new_policies = [ + CatalogDeclarativeIpAllowlistPolicy( + id="admin-vpn-only", + allowed_sources=["203.0.113.10/32", "198.51.100.0/24"], + user_groups=[ + CatalogDeclarativeUserGroupIdentifier(id="group.admins", type="userGroup"), + ], + users=[ + CatalogUserIdentifier(id="employee123", type="user"), + ], + ), + ] + + try: + sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies) + result = sdk.catalog_organization.get_declarative_ip_allowlist_policies() + assert len(result) == 1 + assert result[0].id == "admin-vpn-only" + assert result[0].allowed_sources == ["203.0.113.10/32", "198.51.100.0/24"] + assert len(result[0].user_groups) == 1 + assert result[0].user_groups[0].id == "group.admins" + assert len(result[0].users) == 1 + assert result[0].users[0].id == "employee123" + finally: + sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies) From 71539532b640798c248189f3e75e7307cc741d54 Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Tue, 12 May 2026 08:03:13 +0000 Subject: [PATCH 2/6] fix(gooddata-sdk): [AUTO] fix-agent attempt 1 --- .../layout_ip_allowlist_policies.yaml | 10743 ++++++++++++++++ transcripts/fix-C009-attempt1.jsonl | 127 + 2 files changed, 10870 insertions(+) create mode 100644 packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml create mode 100644 transcripts/fix-C009-attempt1.jsonl diff --git a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml new file mode 100644 index 000000000..4f7da0650 --- /dev/null +++ b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml @@ -0,0 +1,10743 @@ +interactions: + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: + - allowedSources: + - 203.0.113.10/32 + - 198.51.100.0/24 + id: admin-vpn-only + userGroups: + - id: group.admins + type: userGroup + users: + - id: employee123 + type: user + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Some of given referenced ''users'' entities do not exist. Not existing + IDs: [Identifier(employee123)/Organization(default)]' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request +version: 1 diff --git a/transcripts/fix-C009-attempt1.jsonl b/transcripts/fix-C009-attempt1.jsonl new file mode 100644 index 000000000..73d749da3 --- /dev/null +++ b/transcripts/fix-C009-attempt1.jsonl @@ -0,0 +1,127 @@ +{"ts": 1778572545.4825163, "type": "system"} +{"ts": 1778572553.9514349, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me analyze the failing test and understand what's going wrong. The test `test_layout_ip_allowlist_policies` is failing with a 400 Bad Request error during the teardown/restore phase. Let me read the relevant files to understand the issue.\n\nThe error messages in the pytest output are:\n1. First error: `'users' entities do not exist. Not existing IDs: [Identifier(employee123)/Organization(python-sdk-dex)]` - This seems to be related to user validation in the IP allowlist policy\n2. Second error: `Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. \n\nThe second error happens during `put_declarative_ip_allowlist_policies` which calls `set_organization_layout`. The error is about datasource auth properties, which suggests that when we read and write back the organization layout, we're somehow corrupting the datasource configuration. Specifically, the \"demo-test-ds\" datasource is being restored with invalid auth properties\u2014likely a user without a password\u2014which violates the allowed auth combinations.\n\nThis is a classic read-modify-write problem where sensitive fields like passwords get redacted by the API for security, and when we write them back as null or empty, the validation fails.", "truncated": false}]} +{"ts": 1778572553.971637, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01QF9yuxhFAV7Yx2A7Xfg1tA", "input": "{\"file_path\": \"/home/user/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 50}", "truncated": false}]} +{"ts": 1778572554.2598937, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QF9yuxhFAV7Yx2A7Xfg1tA", "is_error": true, "content": "File does not exist. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} +{"ts": 1778572554.2612257, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01PX7FRLn3ovnbFv1PVm4ef6", "input": "{\"file_path\": \"/home/user/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 570, \"limit\": 80}", "truncated": false}]} +{"ts": 1778572554.2953153, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01PX7FRLn3ovnbFv1PVm4ef6", "is_error": true, "content": "File does not exist. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} +{"ts": 1778572556.6449418, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01CUkLHfVURosRfxeTjvfR8p", "input": "{\"command\": \"find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \\\"service.py\\\" -path \\\"*/organization/*\\\" 2>/dev/null\", \"description\": \"Find organization service.py path\"}", "truncated": false}]} +{"ts": 1778572556.6509285, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CUkLHfVURosRfxeTjvfR8p", "is_error": true, "content": "Blocked: find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \"service.py\" -path \"*/organiza", "truncated": false}]} +{"ts": 1778572556.8917181, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01QXCoPyz5TcEB5sC84TaQaD", "input": "{\"command\": \"find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \\\"test_catalog_organization.py\\\" 2>/dev/null\", \"description\": \"Find test file path\"}", "truncated": false}]} +{"ts": 1778572556.9422717, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QXCoPyz5TcEB5sC84TaQaD", "is_error": true, "content": "Blocked: find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \"test_catalog_organization.py\"", "truncated": false}]} +{"ts": 1778572558.987669, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LaCezsuQF8jbuQe3NzWQ2o", "input": "{\"pattern\": \"packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\"}", "truncated": false}]} +{"ts": 1778572559.042493, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LaCezsuQF8jbuQe3NzWQ2o", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py", "truncated": false}]} +{"ts": 1778572559.04287, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01MbEaWCwJrHwSqb7gCJ7Sqy", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\"}", "truncated": false}]} +{"ts": 1778572559.0787725, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MbEaWCwJrHwSqb7gCJ7Sqy", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/test_catalog_organization.py", "truncated": false}]} +{"ts": 1778572561.175191, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GHpK2ms6JGqEL3LYdrhByi", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 60}", "truncated": false}]} +{"ts": 1778572561.5280778, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GHpK2ms6JGqEL3LYdrhByi", "is_error": false, "content": "750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} +{"ts": 1778572561.855271, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DCyTvZ3XB64Gy2ufyZw7qr", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 565, \"limit\": 80}", "truncated": false}]} +{"ts": 1778572561.887425, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DCyTvZ3XB64Gy2ufyZw7qr", "is_error": false, "content": "565\t# sdk.catalog_organization.put_declarative_identity_providers([])\n566\t# idps = sdk.catalog_organization.get_declarative_identity_providers()\n567\t# assert len(idps) == 0\n568\t\n569\t\n570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"group.admins\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"employee123\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"group.admins\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"employee123\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} +{"ts": 1778572571.458231, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the issue. The test uses `gd_vcr.use_cassette` to record/replay API calls, but the cassette file doesn't exist yet. So when the test runs live against a real server, it fails because:\n\n1. The `put_declarative_ip_allowlist_policies` with `new_policies` that contain `employee123` user fails with \"users entities do not exist\" (the employee123 user doesn't exist in the test org).\n\n2. The fallback `put_declarative_ip_allowlist_policies(original_policies)` in the `finally` block also fails because the read-modify-write approach is problematic - when we read the org layout and write it back, sensitive datasource credentials are stripped by the API, and when we PUT them back without the password, the API rejects it with \"Invalid combination of auth properties\".\n\n\nThe real problem is that the read-modify-write pattern for restoring the original policies doesn't work\u2014reading the organization layout strips sensitive fields like datasource passwords, so when we PUT the layout back without those credentials, the API rejects it as invalid.\n\nBut wait, this test uses VCR cassettes for replaying recorded API interactions, so it shouldn't be hitting the real API at all. Let me check if the cassette file actually exists.", "truncated": false}]} +{"ts": 1778572571.4630764, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01JDTxQDtmtE9mh5DeHRF3h5", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/fixtures/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} +{"ts": 1778572571.7129104, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JDTxQDtmtE9mh5DeHRF3h5", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778572571.7146492, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01DM4hX8L6n7oKNNgiww13aC", "input": "{\"command\": \"ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/ | grep -i ip 2>/dev/null || echo \\\"no ip-related fixtures\\\"\", \"description\": \"Check if cassette file exists\"}", "truncated": false}]} +{"ts": 1778572571.8027024, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DM4hX8L6n7oKNNgiww13aC", "is_error": true, "content": "Blocked: ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fi", "truncated": false}]} +{"ts": 1778572573.494986, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01VjDhFFa24n74CWm46My2SM", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/fixtures/*.yaml\"}", "truncated": false}]} +{"ts": 1778572573.5250852, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01VjDhFFa24n74CWm46My2SM", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778572575.964956, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Ao1HHXBxAA2xdpjyhjcdWW", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/**/*.yaml\"}", "truncated": false}]} +{"ts": 1778572575.9876597, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ao1HHXBxAA2xdpjyhjcdWW", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/config/test_translate.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/bigquery.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_cache_strategy.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_data_sources_list.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_delete_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_generate_logical_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_generate_logical_model_sql_datasets.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_load_and_put_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_put_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_put_declarative_data_sources_connection.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_register_upload_notification.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_pdm_and_generate_logical_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_pdm_and_generate_logical_model_sql_datasets.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_schemata.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_store_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model_with_schemata.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model_with_table_prefix.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/dremio.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/patch.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/redshift.yam", "truncated": true}]} +{"ts": 1778572578.5829642, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette file `packages/gooddata-sdk/tests/catalog/fixtures/layout_ip_allowlist_policies.yaml` doesn't exist. The test references `_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"` - let me check where `_fixtures_dir` points to.\n\nLet me also look at how similar tests set up cassette paths to understand what's expected.", "truncated": false}]} +{"ts": 1778572579.5264392, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018sNQAbdPbq7LpWPn15QDNz", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 1, \"limit\": 40}", "truncated": false}]} +{"ts": 1778572579.5604656, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018sNQAbdPbq7LpWPn15QDNz", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\tfrom pathlib import Path\n5\t\n6\tfrom gooddata_api_client.exceptions import NotFoundException\n7\tfrom gooddata_sdk import (\n8\t CatalogCspDirective,\n9\t CatalogDeclarativeIpAllowlistPolicy,\n10\t CatalogDeclarativeNotificationChannel,\n11\t CatalogJwk,\n12\t CatalogOrganization,\n13\t CatalogOrganizationSetting,\n14\t CatalogRsaSpecification,\n15\t CatalogWebhook,\n16\t GoodDataSdk,\n17\t)\n18\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n19\tfrom tests_support.vcrpy_utils import get_vcr\n20\t\n21\tfrom .conftest import safe_delete\n22\t\n23\tgd_vcr = get_vcr()\n24\t\n25\t_default_jwk_id = \"demoJwk\"\n26\t_current_dir = Path(__file__).parent.absolute()\n27\t_fixtures_dir = _current_dir / \"fixtures\" / \"organization\"\n28\t\n29\t\n30\tdef _default_organization_check(organization: CatalogOrganization, test_config: dict):\n31\t # Relaxed assertions \u2014 cassettes may come from local or staging environment,\n32\t # so we only verify the fields are populated, not their exact values.\n33\t assert organization.id\n34\t assert organization.attributes.name\n35\t assert organization.attributes.hostname\n36\t\n37\t\n38\tdef _default_jwk(jwk_id=_default_jwk_id, alg=None, kid=None):\n39\t rsa_specification = CatalogRsaSpecification(\n40\t alg=alg if alg else \"RS256\",", "truncated": false}]} +{"ts": 1778572620.037761, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The `_fixtures_dir` is set to `_current_dir / \"fixtures\" / \"organization\"`, which would be `packages/gooddata-sdk/tests/catalog/fixtures/organization/`. \n\nThe cassette file at `tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml` does NOT exist yet. The ground rules say: \"Do NOT fabricate cassette YAML files \u2014 they will be re-recorded by the pipeline after you finish. Stale cassettes were already deleted.\"\n\nSo the cassette doesn't exist, which means the test is running in \"record\" mode against a live server. The test is failing because:\n\n\nThe first `put_declarative_ip_allowlist_policies(new_policies)` call fails since `employee123` doesn't exist on the server, and the cleanup in the finally block also fails when trying to restore the original policies \u2014 the read returns redacted datasource configs that fail validation on PUT. The real issue is that the test assumes a user that doesn't exist in the environment, and the read-modify-write pattern breaks when the API redacts sensitive fields. Once the cassettes are recorded by the pipeline, this test should pass since it'll replay the recorded responses instead of hitting the live server.\n\nBut I'm realizing the test itself has fundamental problems that would prevent it from recording in the first place. The `employee123` user doesn't exist, so the initial PUT fails immediately. And even if that worked, the cleanup would fail because restoring the original policies hits the auth validation issue with redacted fields. I need to fix the test code itself \u2014 either remove the non-existent user from the policy or swap it for a real user that exists in the test environment, and I need to rethink how the restore logic handles the read-modify-write pattern when sensitive fields get redacted. The instructions are clear\u2014I need to fix only what's necessary for the tests to pass, not redesign the whole approach. The cassette needs to be re-recorded, and there are two issues blocking that: the test references a non-e", "truncated": true}]} +{"ts": 1778572620.0597582, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the API client to check if there's a dedicated endpoint for IP allowlist policies:", "truncated": false}]} +{"ts": 1778572620.066379, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0184RFKAgTbVHcZYRxVdLhyp", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} +{"ts": 1778572620.0687513, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01XGuicks9JZ7yj1x5dsPTvm", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py\"}", "truncated": false}]} +{"ts": 1778572620.0697641, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0184RFKAgTbVHcZYRxVdLhyp", "is_error": true, "content": "Path does not exist: /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} +{"ts": 1778572620.0972176, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XGuicks9JZ7yj1x5dsPTvm", "is_error": false, "content": "1\t# (C) 2025 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\t\n6\tfrom attrs import define, field\n7\tfrom gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n8\t\n9\tfrom gooddata_sdk.catalog.base import Base\n10\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n11\t\n12\t\n13\t@define(kw_only=True)\n14\tclass CatalogDeclarativeIpAllowlistPolicy(Base):\n15\t id: str\n16\t allowed_sources: list[str] = field(factory=list)\n17\t user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list)\n18\t users: list[CatalogUserIdentifier] = field(factory=list)\n19\t\n20\t @staticmethod\n21\t def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]:\n22\t return DeclarativeIpAllowlistPolicy\n23\t", "truncated": false}]} +{"ts": 1778572622.0756288, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HRLih28n3J9dFoGSbmM4nf", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} +{"ts": 1778572622.106803, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HRLih28n3J9dFoGSbmM4nf", "is_error": false, "content": "Found 9 files\ngooddata-api-client/gooddata_api_client/models/__init__.py\ngooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py\ngooddata-api-client/docs/LayoutApi.md\ngooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md\ngooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md\ngooddata-api-client/docs/DeclarativeOrganization.md\ngooddata-api-client/.openapi-generator/FILES\ngooddata-api-client/README.md", "truncated": false}]} +{"ts": 1778572624.3948033, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DZuYQZ299j9yUjx1XW9TDx", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/docs/LayoutApi.md\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572624.7454011, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DZuYQZ299j9yUjx1XW9TDx", "is_error": false, "content": "4438: ip_allowlist_policies=[\n4439: DeclarativeIpAllowlistPolicy(", "truncated": false}]} +{"ts": 1778572624.8203256, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01CKubJVPFqgxbGkjuRM6tX1", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572624.853468, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CKubJVPFqgxbGkjuRM6tX1", "is_error": false, "content": "585: ip_allowlist_policies=[\n586: DeclarativeIpAllowlistPolicy(", "truncated": false}]} +{"ts": 1778572626.9111085, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01WWNiZUnGdcKDfAAnuAhh2M", "input": "{\"pattern\": \"ip_allowlist_polic\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} +{"ts": 1778572626.943843, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WWNiZUnGdcKDfAAnuAhh2M", "is_error": false, "content": "Found 2 files\ngooddata-api-client/gooddata_api_client/models/__init__.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py", "truncated": false}]} +{"ts": 1778572631.0610168, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So there's no dedicated endpoint for IP allowlist policies in the API client. The IP allowlist policies are part of the `DeclarativeOrganization` model. So the read-modify-write approach is the only way.\n\nThe problem is:\n1. The test uses `employee123` user which doesn't exist in the staging environment\n2. The read-modify-write approach fails because the GET response redacts sensitive datasource credentials, and the PUT back fails validation\n\nLet me look at how the `OrganizationDeclarativeAPIsApi` handles these...\n\nLet me check if there's a `put_organization_layout` or similar operation in that API:", "truncated": false}]} +{"ts": 1778572631.7908683, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_017xb7V6HS2XyBkrTCR1SrBo", "input": "{\"pattern\": \"def.*organization_layout|organization_layout.*def\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} +{"ts": 1778572631.8303072, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017xb7V6HS2XyBkrTCR1SrBo", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:479: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:724: def set_organization_layout(\ngooddata-api-client/gooddata_api_client/api/layout_api.py:3550: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/layout_api.py:5870: def set_organization_layout(", "truncated": false}]} +{"ts": 1778572633.7254303, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DoYdf4g3jsyHtzGvbLwY3H", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} +{"ts": 1778572633.7762916, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DoYdf4g3jsyHtzGvbLwY3H", "is_error": false, "content": "1\t\"\"\"\n2\t OpenAPI definition\n3\t\n4\t No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501\n5\t\n6\t The version of the OpenAPI document: v0\n7\t Contact: support@gooddata.com\n8\t Generated by: https://openapi-generator.tech\n9\t\"\"\"\n10\t\n11\t\n12\timport re # noqa: F401\n13\timport sys # noqa: F401\n14\t\n15\tfrom gooddata_api_client.model_utils import ( # noqa: F401\n16\t ApiTypeError,\n17\t ModelComposed,\n18\t ModelNormal,\n19\t ModelSimple,\n20\t cached_property,\n21\t change_keys_js_to_python,\n22\t convert_js_args_to_python_args,\n23\t date,\n24\t datetime,\n25\t file_type,\n26\t none_type,\n27\t validate_get_composed_info,\n28\t OpenApiModel\n29\t)\n30\tfrom gooddata_api_client.exceptions import ApiAttributeError\n31\t\n32\t\n33\tdef lazy_import():\n34\t from gooddata_api_client.model.declarative_agent import DeclarativeAgent\n35\t from gooddata_api_client.model.declarative_custom_geo_collection import DeclarativeCustomGeoCollection\n36\t from gooddata_api_client.model.declarative_data_source import DeclarativeDataSource\n37\t from gooddata_api_client.model.declarative_export_template import DeclarativeExportTemplate\n38\t from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider\n39\t from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n40\t from gooddata_api_client.model.declarative_jwk import DeclarativeJwk\n41\t from gooddata_api_client.model.declarative_notification_channel import DeclarativeNotificationChannel\n42\t from gooddata_api_client.model.declarative_organization_info import DeclarativeOrganizationInfo\n43\t from gooddata_api_client.model.declarative_user import DeclarativeUser\n44\t from gooddata_api_client.model.declarative_user_group import DeclarativeUserGroup\n45\t from gooddata_api_client.model.declarative_workspace import DeclarativeWorkspace\n46\t from gooddata_api_client.mode", "truncated": true}]} +{"ts": 1778572650.682085, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the structure. Let me think about the root cause of the failures:\n\n**Issue 1**: `employee123` user doesn't exist in the staging environment\n**Issue 2**: Read-modify-write approach corrupts datasource auth (returns redacted password in GET, then PUT fails due to missing password)\n\nNow, Issue 2 is the one that's actually crashing the test (in the `finally` block). Issue 1 caused the exception that led to the finally block executing.\n\nThe key question is: what's the right fix here?\n\nLooking at the structure of the problem:\n- The `put_declarative_ip_allowlist_policies` does a full GET of org layout, modifies ip_allowlist_policies, then PUTs the whole thing back\n\n\n- During a live test against staging, the GET returns a datasource with `user: , password: ` (because password is redacted)\n- The PUT then fails because the API requires either both user+password or neither\n\nThis is a fundamental design flaw in the read-modify-write approach for the `put_declarative_ip_allowlist_policies` implementation. The test uses `gd_vcr.use_cassette` to capture and replay HTTP traffic, so once cassettes are recorded, subsequent runs just replay from them. But the cassette file doesn't exist yet, so we need the test to pass during the initial recording phase.\n\nThe instructions say stale cassettes were already deleted and not to fabricate cassette YAML files\u2014they'll be re-recorded by the pipeline. So the real issue is that if the test fails during recording, the cassette won't be created and it'll fail forever. I'm wondering if there's a way to limit what `set_organization_layout` modifies or maybe clear the problematic datasource from the org layout before the PUT, though that feels too invasive. Let me look more closely at the actual error to find a better solution.\n\nThe datasource `demo-test-ds` has a user set but no password, which happens because the GET response redacts passwords. When the PUT sends back the full org layout, the API rejects this invalid auth ", "truncated": true}]} +{"ts": 1778572650.7663822, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HZ9eLeyTMk7UtkSma1w26e", "input": "{\"pattern\": \"put_declarative_notification_channels|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572650.8019989, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HZ9eLeyTMk7UtkSma1w26e", "is_error": false, "content": "647: def put_declarative_notification_channels(\n777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778572652.5978413, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_016jLtpAGwfCcAHkxXyKy6me", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 640, \"limit\": 50}", "truncated": false}]} +{"ts": 1778572652.8133125, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016jLtpAGwfCcAHkxXyKy6me", "is_error": false, "content": "640\t List of declarative notification channels.\n641\t \"\"\"\n642\t return [\n643\t CatalogDeclarativeNotificationChannel.from_api(nc)\n644\t for nc in self._layout_api.get_notification_channels_layout().notification_channels\n645\t ]\n646\t\n647\t def put_declarative_notification_channels(\n648\t self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n649\t ) -> None:\n650\t \"\"\"\n651\t Put declarative notification channels in the current organization.\n652\t\n653\t Args:\n654\t notification_channels (list[CatalogDeclarativeNotificationChannel]):\n655\t List of declarative notification channels.\n656\t\n657\t Returns:\n658\t None\n659\t \"\"\"\n660\t api_ncs = [nc.to_api() for nc in notification_channels]\n661\t self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n662\t\n663\t def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:\n664\t \"\"\"\n665\t Get all declarative identity providers in the current organization.\n666\t\n667\t Returns:\n668\t list[CatalogDeclarativeIdentityProvider]:\n669\t List of declarative identity providers.\n670\t \"\"\"\n671\t return [\n672\t CatalogDeclarativeIdentityProvider.from_api(idp) for idp in self._layout_api.get_identity_providers_layout()\n673\t ]\n674\t\n675\t def put_declarative_identity_providers(self, identity_providers: list[CatalogDeclarativeIdentityProvider]) -> None:\n676\t \"\"\"\n677\t Put declarative identity providers in the current organization.\n678\t\n679\t Args:\n680\t identity_providers (list[CatalogDeclarativeIdentityProvider]):\n681\t List of declarative identity providers.\n682\t\n683\t Returns:\n684\t None\n685\t \"\"\"\n686\t api_idps = [idp.to_api() for idp in identity_providers]\n687\t ", "truncated": true}]} +{"ts": 1778572658.1518195, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! `put_declarative_notification_channels` uses `set_notification_channels` - a *dedicated* endpoint! It doesn't use `set_organization_layout`. Similarly, `put_declarative_identity_providers` uses `set_identity_providers`. \n\nThe prior agent used `set_organization_layout` (read-modify-write) because they thought there was no dedicated endpoint. But let me check if there's a dedicated endpoint for IP allowlist policies in the API client that the prior agent might have missed.\n\nWait, looking at the IP allowlist policies error and the API structure - the prior agent's decision said \"The OpenAPI spec has no dedicated /layout/ipAllowlistPolicies endpoint\". \n\nLet me scan through the available API methods to see if I'm missing a dedicated endpoint for IP allowlist policies.", "truncated": false}]} +{"ts": 1778572658.1547806, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the layout API for any IP allowlist specific endpoints:", "truncated": false}]} +{"ts": 1778572658.5095408, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01LZYcYcL2SCponyFS5umLdz", "input": "{\"command\": \"grep -n \\\"def.*ip\\\\|def.*allowlist\\\\|def.*allow_list\\\\|ip_allowlist\\\\|allowlist\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py 2>/dev/null | head -30\", \"description\": \"Search for IP allowlist methods in layout API\"}", "truncated": false}]} +{"ts": 1778572658.543462, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LZYcYcL2SCponyFS5umLdz", "is_error": true, "content": "Blocked: grep -n \"def.*ip\\|def.*allowlist\\|def.*allow_list\\|ip_allowlist\\|allowlist\" /hom", "truncated": false}]} +{"ts": 1778572660.6904714, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01MEHem5p99BnLt6MK3Rqhya", "input": "{\"pattern\": \"ip_allowlist|allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572660.7279794, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MEHem5p99BnLt6MK3Rqhya", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778572662.7213016, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0131L3RWsspdhSazy5Dso444", "input": "{\"pattern\": \"ip_allowlist|allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572662.7578123, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0131L3RWsspdhSazy5Dso444", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778572686.3569317, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Confirmed: there's no dedicated endpoint for IP allowlist policies in the API. The only way to update them is through the full org layout `set_organization_layout`.\n\nNow the problem is clear: the read-modify-write approach via `set_organization_layout` fails because the GET response redacts datasource credentials, and the PUT back fails because the API requires complete credentials.\n\nThe solution needs to be in either:\n1. The test (which is under `tests/`) - Fix the test to avoid triggering the issue\n2. The implementation (which is in `src/`) - Fix the read-modify-write to not corrupt auth\n\n\nI'm checking how other tests handle `get_organization_layout` to see if any attempt a read-modify-write pattern. Notification channels and identity providers have their own dedicated endpoints, so they avoid this problem entirely. IP allowlist policies are unique in being locked behind the full org layout endpoint. Let me explore whether using the OrganizationDeclarativeAPIsApi instead of LayoutApi could provide a workaround.\n\nActually, both APIs expose the same `get_organization_layout` and `set_organization_layout` methods, so switching APIs won't help. I'm considering whether I could strip out problematic datasources before writing the layout back, but that would delete them entirely\u2014not acceptable. The API doesn't support partial updates either. Looking at the test itself, the first `put` fails because `employee123` doesn't exist in the test org, and I need to figure out what happens in the finally block.\n\nThe core issue is that when I read the org layout, datasource passwords come back redacted, so when I try to write it back, the API rejects the incomplete credentials. I'm wondering if this read-modify-write pattern breaks all operations using `set_organization_layout`, or if it's specific to this test. Let me trace through what's actually happening: the first `put_declarative_ip_allowlist_policies` call modifies the org layout by adding IP allowlist policies with `employe", "truncated": true}]} +{"ts": 1778572686.359743, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how the full org layout is used in other tests and how datasource auth is handled:", "truncated": false}]} +{"ts": 1778572686.497629, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01QGaecwvGQXwGHAkKsRaCoX", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} +{"ts": 1778572686.5297132, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QGaecwvGQXwGHAkKsRaCoX", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778572688.9217331, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01JkJSPaEQWYvfeXP2NEEbsA", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} +{"ts": 1778572689.0322008, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JkJSPaEQWYvfeXP2NEEbsA", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:125: self.get_organization_layout_endpoint = _Endpoint(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:130: 'operation_id': 'get_organization_layout',\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:274: self.set_organization_layout_endpoint = _Endpoint(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:279: 'operation_id': 'set_organization_layout',\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:479: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:489: >>> thread = api.get_organization_layout(async_req=True)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:556: return self.get_organization_layout_endpoint.call_with_http_info(**kwargs)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:724: def set_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:735: >>> thread = api.set_organization_layout(declarative_organization, async_req=True)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:805: return self.set_organization_layout_endpoint.call_with_http_info(**kwargs)\ngooddata-api-client/gooddata_api_clien", "truncated": true}]} +{"ts": 1778572698.21292, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the situation clearly. There's no dedicated endpoint for IP allowlist policies. The only way to set them is via `set_organization_layout`. The read-modify-write approach is the only option.\n\nThe problem is that when the org layout is read, sensitive datasource credentials are redacted. When we write the full org layout back, the API rejects it because the datasource has `user` set but `password` not set.\n\nNow, the real question is: is this something we need to handle in the `put_declarative_ip_allowlist_policies` implementation, or is this something that the test should handle differently?\n\n\nThe cassette-based test approach means once recordings are created, they'll replay without hitting the live server. But to generate those cassettes initially, the test needs to pass against the actual API, which requires either creating the `employee123` user in setup or removing it from the test policy, and also resolving the datasource authentication issue that prevents round-tripping the full org layout.\n\nNow I'm checking how the staging environment's conftest.py handles the snapshot mechanism to understand if there's a way around these constraints.", "truncated": false}]} +{"ts": 1778572698.213881, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest and how similar tests handle read-modify-write patterns:", "truncated": false}]} +{"ts": 1778572698.2323081, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01CVTWAaSanYARtWphAGE843", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 280, \"limit\": 40}", "truncated": false}]} +{"ts": 1778572698.422636, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CVTWAaSanYARtWphAGE843", "is_error": false, "content": "280\t except Exception as e:\n281\t logger.error(f\"Snapshot capture failed [workspace list for permissions]: {e}\")\n282\t snapshot[\"ws_permissions\"] = ws_permissions\n283\t\n284\t logger.info(\"Session snapshot captured\")\n285\t\n286\t # --- Tests run ---\n287\t yield snapshot\n288\t\n289\t # --- Restore (only if failures) ---\n290\t if not _session_has_failures:\n291\t logger.info(\"All tests passed \u2014 skipping session restore\")\n292\t return\n293\t\n294\t logger.warning(\"Test failures detected \u2014 restoring session snapshot...\")\n295\t\n296\t # Restore order matters: users/groups \u2192 data sources \u2192 workspaces \u2192\n297\t # workspace data filters \u2192 org permissions \u2192 notification channels \u2192\n298\t # per-workspace permissions\n299\t\n300\t if \"users_groups\" in snapshot:\n301\t try:\n302\t sdk.catalog_user.put_declarative_users_user_groups(snapshot[\"users_groups\"])\n303\t logger.info(\"Restored [users_groups]\")\n304\t except Exception as e:\n305\t logger.error(f\"RESTORE FAILED [users_groups]: {e}\")\n306\t\n307\t if \"data_sources\" in snapshot:\n308\t try:\n309\t sdk.catalog_data_source.put_declarative_data_sources(snapshot[\"data_sources\"], _credentials_path)\n310\t logger.info(\"Restored [data_sources]\")\n311\t except Exception as e:\n312\t logger.error(f\"RESTORE FAILED [data_sources]: {e}\")\n313\t\n314\t if \"workspaces\" in snapshot:\n315\t try:\n316\t sdk.catalog_workspace.put_declarative_workspaces(snapshot[\"workspaces\"])\n317\t logger.info(\"Restored [workspaces]\")\n318\t except Exception as e:\n319\t logger.error(f\"RESTORE FAILED [workspaces]: {e}\")", "truncated": false}]} +{"ts": 1778572698.4249816, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_013Z982nL8tgf84A3ANRFJxY", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_notification_channels.yaml\", \"offset\": 1, \"limit\": 60}", "truncated": false}]} +{"ts": 1778572698.4610713, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_013Z982nL8tgf84A3ANRFJxY", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\tinteractions:\n3\t - request:\n4\t body:\n5\t notificationChannels:\n6\t - allowedRecipients: CREATOR\n7\t customDashboardUrl: https://dashboard.site\n8\t destination:\n9\t token: '123'\n10\t type: WEBHOOK\n11\t url: https://webhook.site\n12\t id: webhook\n13\t name: Webhook\n14\t headers:\n15\t Accept-Encoding:\n16\t - br, gzip, deflate\n17\t Content-Type:\n18\t - application/json\n19\t X-GDC-VALIDATE-RELATIONS:\n20\t - 'true'\n21\t X-Requested-With:\n22\t - XMLHttpRequest\n23\t method: PUT\n24\t uri: http://localhost:3000/api/v1/layout/notificationChannels\n25\t response:\n26\t body:\n27\t string: ''\n28\t headers:\n29\t DATE: &id001\n30\t - PLACEHOLDER\n31\t Expires:\n32\t - '0'\n33\t Pragma:\n34\t - no-cache\n35\t X-Content-Type-Options:\n36\t - nosniff\n37\t X-GDC-TRACE-ID: *id001\n38\t status:\n39\t code: 204\n40\t message: No Content\n41\t - request:\n42\t body: null\n43\t headers:\n44\t Accept:\n45\t - application/json\n46\t Accept-Encoding:\n47\t - br, gzip, deflate\n48\t X-GDC-VALIDATE-RELATIONS:\n49\t - 'true'\n50\t X-Requested-With:\n51\t - XMLHttpRequest\n52\t method: GET\n53\t uri: http://localhost:3000/api/v1/layout/notificationChannels\n54\t response:\n55\t body:\n56\t string:\n57\t notificationChannels:\n58\t - allowedRecipients: CREATOR\n59\t customDashboardUrl: https://dashboard.site\n60\t dashboardLinkVisibility: INTERNAL_ONLY", "truncated": false}]} +{"ts": 1778572718.6659815, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Key insight from looking at `layout_notification_channels.yaml`:\n- Notification channels use a dedicated `/api/v1/layout/notificationChannels` endpoint (not the full org layout)\n- This is why they work without the datasource auth issue\n\nFor IP allowlist policies, there's no dedicated endpoint. The only option is `set_organization_layout`.\n\nNow let me understand the problem better. When `set_organization_layout` is called, the full org layout (including all datasources with their configurations) needs to be valid.\n\nLooking at the error:\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties... \n\nDatasource: demo-test-ds, user: , password: ...\"}\n```\n\nWhen we read the org layout via `get_organization_layout`, the response omits the datasource passwords. When we try to PUT the full layout back, the API sees a datasource with username but no password, which is an invalid auth combination.\n\nI need to figure out what the actual datasource structure looks like when returned from `get_organization_layout` so I can understand how to properly handle the credentials when updating the layout.\n\nLooking at this differently - the `set_organization_layout` endpoint is a full PUT operation, not a patch, so I need to check if there's a way to preserve existing datasource credentials or if the API allows omitting password fields entirely for datasources that already have credentials stored. I'm wondering if there's a special sentinel value or a different credential field like `token` that handles the \"keep existing\" semantic. Let me check how the `put_declarative_data_sources` method handles this same credential problem.", "truncated": false}]} +{"ts": 1778572718.7396538, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how data sources handle the credential issue:", "truncated": false}]} +{"ts": 1778572718.861483, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01G5vZZqboX8uztL3KUrXJC9", "input": "{\"pattern\": \"put_declarative_data_sources|credentials_path|_credentials\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572718.9779384, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01G5vZZqboX8uztL3KUrXJC9", "is_error": false, "content": "40:from gooddata_sdk.utils import get_ds_credentials, load_all_entities_dict, read_layout_from_file\n155: def put_declarative_data_sources(\n158: credentials_path: Path | None = None,\n167: credentials_path (Optional[Path], optional):\n178: self.test_data_sources_connection(declarative_data_sources, credentials_path, config_file)\n179: credentials = self._credentials_from_file(credentials_path) if credentials_path is not None else None\n223: def load_and_put_declarative_data_sources(\n226: credentials_path: Path | None = None,\n232: This method combines `load_declarative_data_sources` and `put_declarative_data_sources`\n238: credentials_path (Optional[Path], optional):\n249: self.put_declarative_data_sources(data_sources, credentials_path, config_file, test_data_sources)\n437: credentials_path: Path | None = None,\n442: If `credentials_path` is omitted then the connection\n451: credentials_path (Optional[Path], optional):\n465: if credentials_path is not None and config_file is not None:\n467: if credentials_path is not None:\n468: credentials = self._credentials_from_file(credentials_path)\n470: credentials = get_ds_credentials(config_file)\n646: def _credentials_from_file(credentials_path: Path) -> dict[str, Any]:\n647: data = read_layout_from_file(credentials_path)", "truncated": false}]} +{"ts": 1778572729.2555811, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So `put_declarative_data_sources` requires a `credentials_path` to properly handle datasource credentials. This is needed because when reading the layout, credentials are redacted.\n\nThe `set_organization_layout` has the same issue - when you read the full org layout, datasource credentials are redacted, and when you write it back, the API rejects if the credential combination is invalid.\n\nNow let me think about what we can do:\n\n**Approach 1: Handle datasource auth in the org layout write**\nWhen doing `put_declarative_ip_allowlist_policies`, we could clear the auth information from datasources before writing back. But this would break the datasource configurations.\n\n\nWhat if we just omit the datasources entirely from the layout when writing back? That won't work either - it would delete them from the organization.\n\n**Approach 2: Change the test to avoid the issue**\nThe test uses VCR cassettes that record real API calls on first run. The failure is happening during that live recording phase, so maybe we can restructure the test to avoid triggering the PUT failure while still getting the cassette recorded.\n\n**Approach 3: Examine the API endpoint more carefully**\nI should look more closely at `set_organization_layout` to see if there's a parameter to skip datasource credential validation, or if the issue is something else entirely about how the endpoint handles partial updates.\n\nLet me step back and examine how `get_organization_layout` actually returns datasource information and what credential format it uses - that might reveal what's going wrong when we try to write it back.", "truncated": false}]} +{"ts": 1778572729.3141518, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the DeclarativeDataSource model to understand credential handling:", "truncated": false}]} +{"ts": 1778572729.4590197, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01V9phXw5e6XuW1r9cMfE8ea", "input": "{\"pattern\": \"gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\"}", "truncated": false}]} +{"ts": 1778572729.5005705, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01V9phXw5e6XuW1r9cMfE8ea", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/model/declarative_data_source.py", "truncated": false}]} +{"ts": 1778572731.984815, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01TnJUpGMFfqMKyAzp6rwBcE", "input": "{\"pattern\": \"username|password|token|credential|auth\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778572735.0262563, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TnJUpGMFfqMKyAzp6rwBcE", "is_error": false, "content": "95: ('authentication_type',): {\n137: ('password',): {\n146: ('token',): {\n152: ('username',): {\n185: 'authentication_type': (str, none_type,), # noqa: E501\n192: 'password': (str,), # noqa: E501\n196: 'token': (str,), # noqa: E501\n198: 'username': (str,), # noqa: E501\n212: 'authentication_type': 'authenticationType', # noqa: E501\n219: 'password': 'password', # noqa: E501\n223: 'token': 'token', # noqa: E501\n225: 'username': 'username', # noqa: E501\n276: authentication_type (str, none_type): Type of authentication used to connect to the database.. [optional] # noqa: E501\n283: password (str): Password for the data-source user, property is never returned back.. [optional] # noqa: E501\n287: token (str): Token as an alternative to username and password.. [optional] # noqa: E501\n289: username (str): User with permission connect the data source/database.. [optional] # noqa: E501\n386: authentication_type (str, none_type): Type of authentication used to connect to the database.. [optional] # noqa: E501\n393: password (str): Password for the data-source user, property is never returned back.. [optional] # noqa: E501\n397: token (str): Token as an alternative to username and password.. [optional] # noqa: E501\n399: username (str): User with permission connect the data source/database.. [optional] # noqa: E501", "truncated": false}]} +{"ts": 1778572750.1914165, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Key finding: `password (str): Password for the data-source user, property is never returned back.`\n\nSo the password is NEVER returned by the API. When you GET the org layout, datasources will have `username` set but `password` absent (because it's never returned). When you PUT the layout back with `username` but no `password`, the API rejects it.\n\nThis means the read-modify-write approach for `set_organization_layout` is fundamentally broken for organizations that have datasources with username/password authentication.\n\nNow let me look at what options we have:\n\n\n1. **Use a dedicated layout endpoint** - there isn't one for IP allowlist policies\n2. **Strip auth from datasources** - would break datasources \n3. **Set datasources to empty list** - would delete datasources\n4. **Use `token` auth approach** - not applicable\n5. **Skip credential validation somehow** - the `set_organization_layout` doesn't seem to have such an option\n6. **Change the test to use a cassette that avoids the issue** - the cassette would need to be fabricated\n\nThe instructions say \"Do NOT fabricate cassette YAML files\", but maybe I can create a valid cassette by recording an actual interaction that sidesteps this problem.\n\nLet me reconsider the `set_organization_layout` endpoint itself. What if I could pass a `DeclarativeOrganization` with an empty datasources list to avoid the auth validation issue? Though that would wipe out all datasources. Or maybe the endpoint has a parameter like `skip_credentials` or only requires datasources if you're actually modifying them\u2014in which case omitting them might preserve the existing ones. Let me check the endpoint documentation more carefully to see if datasources are truly required or if they're only needed when making changes.\n\nActually, I'm noticing that the notification channels test works fine because it uses a dedicated `/api/v1/layout/notificationChannels` endpoint rather than the full organization layout endpoint. The `get_declarative_notification_cha", "truncated": true}]} +{"ts": 1778572750.1981776, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check what other layout API methods exist:", "truncated": false}]} +{"ts": 1778572750.2792304, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Ez8BVJGnduSi3M3h1V5bcA", "input": "{\"pattern\": \"def (get|set|put)_.*layout\\\\b|def (get|set|put)_.*policies\\\\b|def.*ip_allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572750.3185189, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ez8BVJGnduSi3M3h1V5bcA", "is_error": false, "content": "2578: def get_agents_layout(\n2824: def get_custom_geo_collections_layout(\n3070: def get_data_sources_layout(\n3148: def get_export_templates_layout(\n3310: def get_identity_providers_layout(\n3472: def get_notification_channels_layout(\n3550: def get_organization_layout(\n3873: def get_user_groups_layout(\n4034: def get_users_layout(\n4112: def get_users_user_groups_layout(\n4190: def get_workspace_data_filters_layout(\n4268: def get_workspace_layout(\n4435: def get_workspaces_layout(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5870: def set_organization_layout(\n6297: def set_workspace_data_filters_layout(\n6467: def set_workspaces_layout(", "truncated": false}]} +{"ts": 1778572786.6973083, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the available API methods, there's no dedicated endpoint for IP allowlist policies. The only option is `set_organization_layout`.\n\nNow I need to understand the actual fix needed. Let me review the error:\n\nThe `set_organization_layout` fails because:\n1. The org layout GET response returns a datasource with `username` but no `password`\n2. When this is PUT back, the API rejects it as invalid combination\n\nThe issue is that the implementation reads the full org layout (which includes datasources with redacted credentials) and then writes it back, which causes the datasource auth issue.\n\n\nI'm considering several approaches to fix this: stripping datasources entirely would delete them, setting the password to an empty string might not work, clearing the username when password is missing could corrupt data, or somehow excluding datasources from the write operation. Let me think through what's actually happening here.\n\nThe core issue is that the API returns datasources with redacted credentials on GET, and then rejects the PUT when we send them back without passwords. I'm wondering if there's a way to preserve the datasources on the server side rather than trying to send them back\u2014maybe the test environment's staging datasource with redacted credentials is the real blocker, and I need to find a different approach entirely. environment, you'd need to provide credentials when doing the full org layout PUT.\n\nBut the notification channels test works fine because it uses a DEDICATED endpoint that doesn't touch datasources.\n\nThe real question: is there ANY way to do this test in the staging environment given the constraints?\n\nLet me look at the `layout_notification_channels.yaml` cassette more carefully to understand how cassettes work. If the cassette exists, the test doesn't make real HTTP calls - it replays from the cassette. \n\nThe test has `@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))`. If this cassette existed with valid responses,", "truncated": true}]} +{"ts": 1778572786.7196512, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the `DeclarativeOrganization` model more carefully:", "truncated": false}]} +{"ts": 1778572786.9827282, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_017HrHqD55dtG82kQAFUJkrw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 80, \"limit\": 120}", "truncated": false}]} +{"ts": 1778572787.0186925, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017HrHqD55dtG82kQAFUJkrw", "is_error": false, "content": "80\t min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,\n81\t inclusive_minimum, and regex.\n82\t additional_properties_type (tuple): A tuple of classes accepted\n83\t as additional properties values.\n84\t \"\"\"\n85\t\n86\t allowed_values = {\n87\t }\n88\t\n89\t validations = {\n90\t }\n91\t\n92\t @cached_property\n93\t def additional_properties_type():\n94\t \"\"\"\n95\t This must be a method because a model may have properties that are\n96\t of type self, this must run after the class is loaded\n97\t \"\"\"\n98\t lazy_import()\n99\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n100\t\n101\t _nullable = False\n102\t\n103\t @cached_property\n104\t def openapi_types():\n105\t \"\"\"\n106\t This must be a method because a model may have properties that are\n107\t of type self, this must run after the class is loaded\n108\t\n109\t Returns\n110\t openapi_types (dict): The key is attribute name\n111\t and the value is attribute type.\n112\t \"\"\"\n113\t lazy_import()\n114\t return {\n115\t 'organization': (DeclarativeOrganizationInfo,), # noqa: E501\n116\t 'agents': ([DeclarativeAgent],), # noqa: E501\n117\t 'custom_geo_collections': ([DeclarativeCustomGeoCollection],), # noqa: E501\n118\t 'data_sources': ([DeclarativeDataSource],), # noqa: E501\n119\t 'export_templates': ([DeclarativeExportTemplate],), # noqa: E501\n120\t 'identity_providers': ([DeclarativeIdentityProvider],), # noqa: E501\n121\t 'ip_allowlist_policies': ([DeclarativeIpAllowlistPolicy],), # noqa: E501\n122\t 'jwks': ([DeclarativeJwk],), # noqa: E501\n123\t 'notification_channels': ([DeclarativeNotificationChannel],), # noqa: E501\n124\t 'user_groups': ([DeclarativeUserGroup],), # noqa: E501\n125\t 'users': ([DeclarativeUser],), # noqa: E501\n12", "truncated": true}]} +{"ts": 1778572844.980338, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see that `data_sources` is optional (not required) in `DeclarativeOrganization`. The only required field is `organization`. \n\nNow the question is: if we do `get_organization_layout()` and get back an org layout object with `data_sources` containing datasources with redacted credentials, can we set `org_layout.data_sources = ???` to avoid the auth issue?\n\nLooking at how the API model works with `_check_return_type=False` - the model is returned as a ModelNormal instance where attributes are stored. If we could delete the `data_sources` attribute from the returned object (or set it in a way that it won't be included in the serialized body), that might avoid the issue.\n\n\nBut removing `data_sources` from the PUT body raises a bigger question: would the API preserve existing data sources or wipe them out? Since this is a full PUT operation, the behavior is unclear. Searching through the codebase, I notice that `set_organization_layout` is only used in one place\u2014the IP allowlist policies implementation\u2014which means there's no established pattern for how to handle read-modify-write operations on the full org layout.\n\nThe prior agent introduced a novel approach that's never been tested with actual datasource credentials. I'm weighing three options: fix the test to avoid non-existent users, modify the implementation to preserve datasource credentials during the PUT, or completely rethink the approach. For the second option, I'm wondering if omitting the `data_sources` field entirely would let the API keep existing datasources intact, since the model likely has all fields as optional.\n\nActually, the API uses a declarative PUT pattern\u2014what you send is what you get\u2014so omitting `data_sources` would probably delete them all. But I'm realizing the `_check_return_type=False` flag might be key here. When the model is returned without type checking, setting attributes like `ip_allowlist_policies` on that object and then serializing it back should include all those attributes in the ", "truncated": true}]} +{"ts": 1778572844.9868765, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at an existing organization layout cassette to understand the structure:", "truncated": false}]} +{"ts": 1778572845.0421576, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_016mcHaHP7qcZ26gcNg1QLDq", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/organization.yaml\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} +{"ts": 1778572845.0793655, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016mcHaHP7qcZ26gcNg1QLDq", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\tinteractions:\n3\t - request:\n4\t body: null\n5\t headers:\n6\t Accept-Encoding:\n7\t - br, gzip, deflate\n8\t X-GDC-VALIDATE-RELATIONS:\n9\t - 'true'\n10\t X-Requested-With:\n11\t - XMLHttpRequest\n12\t method: GET\n13\t uri: http://localhost:3000/api/v1/entities/organization\n14\t response:\n15\t body:\n16\t string: ''\n17\t headers:\n18\t Content-Type:\n19\t - application/vnd.gooddata.api+json\n20\t DATE: &id001\n21\t - PLACEHOLDER\n22\t Expires:\n23\t - '0'\n24\t Location:\n25\t - /api/v1/entities/admin/organizations/default\n26\t Pragma:\n27\t - no-cache\n28\t X-Content-Type-Options:\n29\t - nosniff\n30\t X-GDC-TRACE-ID: *id001\n31\t status:\n32\t code: 302\n33\t message: Found\n34\t - request:\n35\t body: null\n36\t headers:\n37\t Accept-Encoding:\n38\t - br, gzip, deflate\n39\t X-GDC-VALIDATE-RELATIONS:\n40\t - 'true'\n41\t X-Requested-With:\n42\t - XMLHttpRequest\n43\t method: GET\n44\t uri: http://localhost:3000/api/v1/entities/admin/organizations/default\n45\t response:\n46\t body:\n47\t string:\n48\t data:\n49\t attributes:\n50\t allowedOrigins: []", "truncated": false}]} +{"ts": 1778572872.1974902, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK, this is the entities API, not the layout API. Let me look at if there are any cassettes that use `get_organization_layout` or `set_organization_layout` to understand the format.\n\nActually wait, I realize from all the existing cassettes that none of them use `set_organization_layout`. This is a new operation being introduced by the IP allowlist policy feature.\n\nLet me now think about what the ACTUAL minimal fix should be.\n\nGiven the constraints:\n1. No dedicated endpoint for IP allowlist policies\n2. `set_organization_layout` fails when org has datasources with username but redacted password\n3. The test cassette doesn't exist yet and needs to be recorded\n\n\n4. Can't fabricate cassettes\n\nThe only fix that would make the test pass in a live environment is to either fix the implementation to not use `set_organization_layout` (but there's no other option) or make `put_declarative_ip_allowlist_policies` handle the datasource credential issue. One approach could be stripping the `data_sources` from the org layout before the PUT, though that would delete datasources. Alternatively, I could examine what happens when the org layout GET response uses `_check_return_type=False` and see if the datasource objects have specific properties I can detect and handle.\n\nWhen the model is returned without validation, the datasource object would have `username` set but `password` missing since the API never returns it. I could try detecting this and clearing the username, but that corrupts the data. Or I could change the `authentication_type` to something that doesn't require a password, though I'm not sure what valid values exist without access to the API documentation. Let me step back and look at the actual error message to find a different angle.\n\nThe error lists the only valid auth combinations: `none`, `user + password`, `token`, `key-pair`, or `clientId + clientSecret`. When the org layout is read, a datasource with username/password auth ends up with `username` set but `password`", "truncated": true}]} +{"ts": 1778572872.2001908, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the VCR configuration for the tests:", "truncated": false}]} +{"ts": 1778572872.2850714, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DFdYTmi2h1SR1NQ9j6tK1E", "input": "{\"pattern\": \"get_vcr|record_mode|vcr|cassette\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\", \"glob\": \"vcrpy_utils.py\"}", "truncated": false}]} +{"ts": 1778572872.3260367, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DFdYTmi2h1SR1NQ9j6tK1E", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778572874.493352, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LS9sja4Fmt5vNMBs25Ecuy", "input": "{\"pattern\": \"**/*vcrpy*\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778572874.5524855, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LS9sja4Fmt5vNMBs25Ecuy", "is_error": false, "content": "packages/tests-support/src/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/__pycache__/vcrpy_utils.cpython-312.pyc", "truncated": false}]} +{"ts": 1778572876.1760314, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01LWCpAa914dx2CiMtbtGtyL", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\"}", "truncated": false}]} +{"ts": 1778572876.2793794, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LWCpAa914dx2CiMtbtGtyL", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} +{"ts": 1778572923.5691607, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the VCR setup:\n```python\nrecord_mode=RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE,\n```\n\nWith `RecordMode.ONCE`: if the cassette file exists, it will replay from it. If it doesn't exist, it will record new cassettes.\n\nSince the cassette `layout_ip_allowlist_policies.yaml` doesn't exist, the test is running in record mode, making real API calls to the staging server. The API calls are failing because:\n1. `employee123` user doesn't exist in the staging environment\n\n\n2. The `set_organization_layout` call fails when trying to update with redacted datasource credentials\n\nThe recording can't succeed until both issues are resolved. The core problem is that `put_declarative_ip_allowlist_policies` uses `set_organization_layout` to update just the IP allowlist policies, but it needs the full organization layout. When the GET returns the layout with redacted datasource credentials, the PUT rejects those redacted values.\n\nLooking at the error more carefully, the failure happens in the finally block where we're trying to restore the original policies. The initial PUT fails because `employee123` doesn't exist in the staging environment, and then the restore attempt fails because of the datasource credential issue. I need to either remove the non-existent user from the test data or find a valid user ID that exists in staging, but we don't have visibility into what users are available there.\n\nFor the datasource auth problem, I'm wondering if there's a way to exclude datasources from the request entirely\u2014maybe the API preserves existing datasources when they're not included in the payload. But that's speculative. Let me look at how other similar tests handle this, like the notification channels test, which uses a dedicated endpoint that only deals with notification channels rather than the entire organization layout.\n\nThe real issue is that there's no dedicated endpoint for IP allowlist policies, so we're forced to use `set_organization_layout`. But tha", "truncated": true}]} +{"ts": 1778572923.5706112, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the notification channels test for comparison:", "truncated": false}]} +{"ts": 1778572923.5874326, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_015tsNXag2jrgC1q9AhrRPXE", "input": "{\"pattern\": \"test.*notification_channel|layout_notification_channel\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778572923.6184525, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015tsNXag2jrgC1q9AhrRPXE", "is_error": false, "content": "316:@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_notification_channels.yaml\"))\n317:def test_layout_notification_channels(test_config, snapshot_notification_channels):", "truncated": false}]} +{"ts": 1778572925.6630418, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Gu47JLD94ijuKThj9ZX2d5", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 316, \"limit\": 60}", "truncated": false}]} +{"ts": 1778572925.7660956, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Gu47JLD94ijuKThj9ZX2d5", "is_error": false, "content": "316\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_notification_channels.yaml\"))\n317\tdef test_layout_notification_channels(test_config, snapshot_notification_channels):\n318\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n319\t\n320\t notification_channels_e = [\n321\t CatalogDeclarativeNotificationChannel(\n322\t id=\"webhook\",\n323\t name=\"Webhook\",\n324\t destination=CatalogWebhook(url=\"https://webhook.site\", token=\"123\"),\n325\t custom_dashboard_url=\"https://dashboard.site\",\n326\t allowed_recipients=\"CREATOR\",\n327\t ),\n328\t ]\n329\t sdk.catalog_organization.put_declarative_notification_channels(notification_channels_e)\n330\t notification_channels_o = sdk.catalog_organization.get_declarative_notification_channels()\n331\t assert notification_channels_e[0].id == notification_channels_o[0].id\n332\t assert notification_channels_e[0].name == notification_channels_o[0].name\n333\t assert notification_channels_e[0].destination == notification_channels_o[0].destination\n334\t assert notification_channels_e[0].custom_dashboard_url == notification_channels_o[0].custom_dashboard_url\n335\t assert notification_channels_e[0].allowed_recipients == notification_channels_o[0].allowed_recipients\n336\t # snapshot_notification_channels fixture restores original state in teardown\n337\t\n338\t\n339\t#\n340\t# The following tests are commented out as they require the organization to have the FEDERATED_IDENTITY_MANAGEMENT\n341\t# entitlement enabled which cannot be done via SDK and must be done by GoodData support.\n342\t#\n343\t# @gd_vcr.use_cassette(str(_fixtures_dir / \"create_identity_provider.yaml\"))\n344\t# def test_create_identity_provider(test_config):\n345\t# sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n346\t#\n347\t# identity_provider_id = \"test_identity_provider\"\n348\t# custom_claim_mapping = {\"email\": \"email\"}\n349\t# identifiers = [\"goodt", "truncated": true}]} +{"ts": 1778572928.1773582, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see! The `test_layout_notification_channels` test uses a `snapshot_notification_channels` fixture that restores original state in teardown. It doesn't use a `try/finally` block for restoration. The fixture handles the restore.\n\nLet me look at the `snapshot_notification_channels` fixture to understand how it works:", "truncated": false}]} +{"ts": 1778572928.5660772, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest for the organization tests:", "truncated": false}]} +{"ts": 1778572928.75303, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01UEsmsNsCX2wvbpXsMRy89X", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/conftest.py\"}", "truncated": false}]} +{"ts": 1778572928.7854345, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UEsmsNsCX2wvbpXsMRy89X", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\t\"\"\"\n3\tShared test fixtures for catalog tests.\n4\t\n5\tProvides:\n6\t- safe_delete: cleanup utility that swallows exceptions\n7\t- sdk: session-scoped GoodDataSdk instance\n8\t- Snapshot/restore fixtures for staging-safe testing\n9\t\"\"\"\n10\t\n11\tfrom __future__ import annotations\n12\t\n13\timport copy\n14\timport logging\n15\tfrom pathlib import Path\n16\tfrom typing import Any, Callable\n17\t\n18\timport pytest\n19\tfrom gooddata_sdk import CatalogDeclarativeDataSources, GoodDataSdk\n20\tfrom tests_support.file_utils import load_json\n21\t\n22\tlogger = logging.getLogger(__name__)\n23\t\n24\t_current_dir = Path(__file__).parent.absolute()\n25\t_credentials_path = _current_dir / \"load\" / \"data_source_credentials\" / \"data_sources_credentials.yaml\"\n26\t\n27\t\n28\tdef _capture_workspace_permissions(sdk: GoodDataSdk, workspaces: list) -> dict:\n29\t \"\"\"Capture permissions for all workspaces, skipping failures.\"\"\"\n30\t ws_permissions: dict = {}\n31\t for ws in workspaces:\n32\t try:\n33\t ws_permissions[ws.id] = sdk.catalog_permission.get_declarative_permissions(ws.id)\n34\t except Exception as e: # noqa: PERF203\n35\t logger.warning(f\"Could not capture permissions for workspace {ws.id}: {e}\")\n36\t return ws_permissions\n37\t\n38\t\n39\tdef _restore_workspace_permissions(sdk: GoodDataSdk, ws_permissions: dict) -> None:\n40\t \"\"\"Restore permissions for all workspaces, logging failures.\"\"\"\n41\t for ws_id, perms in ws_permissions.items():\n42\t try:\n43\t sdk.catalog_permission.put_declarative_permissions(ws_id, perms)\n44\t except Exception as e: # noqa: PERF203\n45\t logger.warning(f\"RESTORE FAILED [permissions for {ws_id}]: {e}\")\n46\t\n47\t\n48\tdef safe_delete(func: Callable, *args: Any, **kwargs: Any) -> None:\n49\t \"\"\"Call a cleanup function, swallowing any exception so it doesn't mask test failures.\n50\t\n51\t Use this in `finally` blocks instead of bare cleanup calls.\n52\t \"\"\"\n53\t try:\n54\t func(*args, **kwa", "truncated": true}]} +{"ts": 1778572943.5736, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! The conftest has a `snapshot_notification_channels` fixture that:\n1. Gets current notification channels\n2. Yields (test runs)\n3. After the test, restores the original notification channels\n\nThe `test_layout_notification_channels` test uses this fixture instead of a manual try/finally block.\n\nThe key difference between the IP allowlist test and the notification channels test:\n\n**Notification channels**: Uses a dedicated endpoint (`get_notification_channels_layout` / `set_notification_channels`). No datasource credential issue.\n\n**IP allowlist policies**: No dedicated endpoint, must use `set_organization_layout`. \n\nThis fails when the org has datasources with redacted credentials. I need to decide between two approaches: fixing the test by removing the problematic user and switching to a proper fixture, or fixing the implementation by handling the credential issue in `set_organization_layout`. The real solution is probably in the implementation\u2014when reading the org layout to modify IP allowlist policies, I should preserve existing datasource credentials instead of letting them get redacted.\n\nThe tricky part is that the API returns `username` without `password` for security, but if I PUT back with just `username` set, it might either clear the auth or fail validation. I need to check whether omitting `username` from the PUT body preserves the existing credential, or if I need a different approach entirely.\n\nLet me look at the `DeclarativeDataSource` model to see if `username` is actually optional\u2014if it is, maybe I can omit it from the PUT request entirely and the API will leave the existing credentials untouched.", "truncated": false}]} +{"ts": 1778572943.5863879, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the optional keys in `DeclarativeDataSource`:", "truncated": false}]} +{"ts": 1778572943.62274, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018VWrweuqRJzju9YuZ6FKxe", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 155, \"limit\": 80}", "truncated": false}]} +{"ts": 1778572943.7220423, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018VWrweuqRJzju9YuZ6FKxe", "is_error": false, "content": "155\t }\n156\t\n157\t @cached_property\n158\t def additional_properties_type():\n159\t \"\"\"\n160\t This must be a method because a model may have properties that are\n161\t of type self, this must run after the class is loaded\n162\t \"\"\"\n163\t lazy_import()\n164\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n165\t\n166\t _nullable = False\n167\t\n168\t @cached_property\n169\t def openapi_types():\n170\t \"\"\"\n171\t This must be a method because a model may have properties that are\n172\t of type self, this must run after the class is loaded\n173\t\n174\t Returns\n175\t openapi_types (dict): The key is attribute name\n176\t and the value is attribute type.\n177\t \"\"\"\n178\t lazy_import()\n179\t return {\n180\t 'id': (str,), # noqa: E501\n181\t 'name': (str,), # noqa: E501\n182\t 'schema': (str,), # noqa: E501\n183\t 'type': (str,), # noqa: E501\n184\t 'alternative_data_source_id': (str, none_type,), # noqa: E501\n185\t 'authentication_type': (str, none_type,), # noqa: E501\n186\t 'cache_strategy': (str,), # noqa: E501\n187\t 'client_id': (str,), # noqa: E501\n188\t 'client_secret': (str,), # noqa: E501\n189\t 'date_time_semantics': (str, none_type,), # noqa: E501\n190\t 'decoded_parameters': ([Parameter],), # noqa: E501\n191\t 'parameters': ([Parameter],), # noqa: E501\n192\t 'password': (str,), # noqa: E501\n193\t 'permissions': ([DeclarativeDataSourcePermission],), # noqa: E501\n194\t 'private_key': (str, none_type,), # noqa: E501\n195\t 'private_key_passphrase': (str, none_type,), # noqa: E501\n196\t 'token': (str,), # noqa: E501\n197\t 'url': (str,), # noqa: E501\n198\t 'username': (str,), # noqa: E501\n199\t }\n200\t\n201\t @cached_property\n202\t ", "truncated": true}]} +{"ts": 1778572945.8482208, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DNiKcgMEeAfUBPJjQur5dG", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 234, \"limit\": 60}", "truncated": false}]} +{"ts": 1778572945.8852603, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DNiKcgMEeAfUBPJjQur5dG", "is_error": false, "content": "234\t @convert_js_args_to_python_args\n235\t def _from_openapi_data(cls, id, name, schema, type, *args, **kwargs): # noqa: E501\n236\t \"\"\"DeclarativeDataSource - a model defined in OpenAPI\n237\t\n238\t Args:\n239\t id (str): Data source ID.\n240\t name (str): Name of the data source.\n241\t schema (str): A scheme/database with the data.\n242\t type (str): Type of database.\n243\t\n244\t Keyword Args:\n245\t _check_type (bool): if True, values for parameters in openapi_types\n246\t will be type checked and a TypeError will be\n247\t raised if the wrong type is input.\n248\t Defaults to True\n249\t _path_to_item (tuple/list): This is a list of keys or values to\n250\t drill down to the model in received_data\n251\t when deserializing a response\n252\t _spec_property_naming (bool): True if the variable names in the input data\n253\t are serialized names, as specified in the OpenAPI document.\n254\t False if the variable names in the input data\n255\t are pythonic names, e.g. snake case (default)\n256\t _configuration (Configuration): the instance to use when\n257\t deserializing a file_type parameter.\n258\t If passed, type conversion is attempted\n259\t If omitted no type conversion is done.\n260\t _visited_composed_classes (tuple): This stores a tuple of\n261\t classes that we have traveled through so that\n262\t if we see that class again we will not use its\n263\t discriminator again.\n264\t When traveling through a discriminator, the\n265\t ", "truncated": true}]} +{"ts": 1778572981.8116634, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see that `username` is optional. So when the GET response returns the org layout, the datasource object has `username` set but `password` NOT set (it's never returned).\n\nThe `_check_return_type=False` flag is key here. Let me look at how the `ModelNormal` works when `_check_return_type=False`. When we do `get_organization_layout(_check_return_type=False)`, the returned object is a raw dict-like object (ModelNormal) where:\n- `username` is set (e.g., \"some_user\")\n\n\n- `password` is NOT present in the object\n\nWhen we serialize this back via `set_organization_layout`, the serializer includes `username` but not `password`. The API then sees username without password and rejects it.\n\nI could delete the `username` attribute from each datasource before the PUT, but that would strip the auth type entirely and break the datasource connection in staging. The conftest's session-level restore would only fix this if tests fail, which they currently do.\n\nLet me trace through the error flow more carefully to understand what's actually happening.\n\nLooking at the pytest output, the first error is that `employee123` doesn't exist when we try to PUT the new policies. Then in the finally block when we attempt to restore the original policies, we hit a different error about invalid datasource auth combinations.\n\nSo the sequence is: the first PUT fails because of the non-existent user, not the datasource auth issue. The datasource auth problem only surfaces when we try to restore in the cleanup. but the underlying issue is that the datasource auth validation happens regardless of what policies are being set. The real problem is that the test environment itself has auth configuration issues that prevent any PUT operation on this endpoint from succeeding, whether it's adding new policies or restoring the original state.\n\nThe minimal fix would be to strip the `data_sources` field from the org layout before sending the PUT request, but I need to figure out whether omitting the field entirely", "truncated": true}]} +{"ts": 1778572981.8296227, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the set_agents_layout endpoint to understand partial update patterns:", "truncated": false}]} +{"ts": 1778572981.8298998, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Vk35knDsajRSWKwTUsiik6", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 5020, \"limit\": 60}", "truncated": false}]} +{"ts": 1778572981.8514466, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Vk35knDsajRSWKwTUsiik6", "is_error": false, "content": "5020\t def set_agents_layout(\n5021\t self,\n5022\t declarative_agents,\n5023\t **kwargs\n5024\t ):\n5025\t \"\"\"Set all AI agent configurations # noqa: E501\n5026\t\n5027\t Sets AI agent configurations in organization. # noqa: E501\n5028\t This method makes a synchronous HTTP request by default. To make an\n5029\t asynchronous HTTP request, please pass async_req=True\n5030\t\n5031\t >>> thread = api.set_agents_layout(declarative_agents, async_req=True)\n5032\t >>> result = thread.get()\n5033\t\n5034\t Args:\n5035\t declarative_agents (DeclarativeAgents):\n5036\t\n5037\t Keyword Args:\n5038\t _return_http_data_only (bool): response data without head status\n5039\t code and headers. Default is True.\n5040\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n5041\t will be returned without reading/decoding response data.\n5042\t Default is True.\n5043\t _request_timeout (int/float/tuple): timeout setting for this request. If\n5044\t one number provided, it will be total request timeout. It can also\n5045\t be a pair (tuple) of (connection, read) timeouts.\n5046\t Default is None.\n5047\t _check_input_type (bool): specifies if type checking\n5048\t should be done one the data sent to the server.\n5049\t Default is True.\n5050\t _check_return_type (bool): specifies if type checking\n5051\t should be done one the data received from the server.\n5052\t Default is True.\n5053\t _spec_property_naming (bool): True if the variable names in the input data\n5054\t are serialized names, as specified in the OpenAPI document.\n5055\t False if the variable names in the input data\n5056\t are pythonic names, e.g. snake case (default)\n5057\t _content_type (str/None): force body co", "truncated": true}]} +{"ts": 1778572983.95781, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01HvtrpuCtcy9pYJtaE8Fpey", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 2086, \"limit\": 30}", "truncated": false}]} +{"ts": 1778572983.9970124, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HvtrpuCtcy9pYJtaE8Fpey", "is_error": false, "content": "2086\t self.set_organization_layout_endpoint = _Endpoint(\n2087\t settings={\n2088\t 'response_type': None,\n2089\t 'auth': [],\n2090\t 'endpoint_path': '/api/v1/layout/organization',\n2091\t 'operation_id': 'set_organization_layout',\n2092\t 'http_method': 'PUT',\n2093\t 'servers': None,\n2094\t },\n2095\t params_map={\n2096\t 'all': [\n2097\t 'declarative_organization',\n2098\t ],\n2099\t 'required': [\n2100\t 'declarative_organization',\n2101\t ],\n2102\t 'nullable': [\n2103\t ],\n2104\t 'enum': [\n2105\t ],\n2106\t 'validation': [\n2107\t ]\n2108\t },\n2109\t root_map={\n2110\t 'validations': {\n2111\t },\n2112\t 'allowed_values': {\n2113\t },\n2114\t 'openapi_types': {\n2115\t 'declarative_organization':", "truncated": false}]} +{"ts": 1778572993.3206413, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The `set_organization_layout` endpoint is `/api/v1/layout/organization` with HTTP method PUT. It takes a `DeclarativeOrganization` which is a required parameter. \n\nLet me now look at how the `set_organization_layout` handles missing fields in the body. When we pass a `DeclarativeOrganization` that doesn't have `data_sources` set, what happens?\n\nActually, looking at this more carefully: when we get the org_layout with `_check_return_type=False`, the returned object is a `ModelNormal` that has all the fields set based on the API response. The `data_sources` field would be set in the `_data_store` of the model.\n \nWhen I modify `org_layout.ip_allowlist_policies = [...]`, I'm updating a field on the object. If I could somehow remove `data_sources` from the `_data_store` before calling `set_organization_layout`, the serialized PUT request wouldn't include it\u2014and I'm wondering what the API does when that field is omitted from the request body.\n\nThe key issue is whether `data_sources` is truly optional in the endpoint and the API preserves existing datasources when they're not included, or if it deletes them when they're missing from the request. I need to check the actual API documentation or cassettes to understand the semantics of the `set_organization_layout` PUT operation.", "truncated": false}]} From b536f2f5aa8f1798bac6f2487cfd38bae0664a1e Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Tue, 12 May 2026 08:12:32 +0000 Subject: [PATCH 3/6] fix(gooddata-sdk): [AUTO] fix-agent attempt 2 --- .../layout_ip_allowlist_policies.yaml | 10740 ++++++++++++++++ transcripts/fix-C009-attempt2.jsonl | 144 + 2 files changed, 10884 insertions(+) create mode 100644 transcripts/fix-C009-attempt2.jsonl diff --git a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml index 4f7da0650..70642f078 100644 --- a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml +++ b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml @@ -10740,4 +10740,10744 @@ interactions: status: code: 400 message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: + - allowedSources: + - 203.0.113.10/32 + - 198.51.100.0/24 + id: admin-vpn-only + userGroups: + - id: group.admins + type: userGroup + users: + - id: employee123 + type: user + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Some of given referenced ''users'' entities do not exist. Not existing + IDs: [Identifier(employee123)/Organization(default)]' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request version: 1 diff --git a/transcripts/fix-C009-attempt2.jsonl b/transcripts/fix-C009-attempt2.jsonl new file mode 100644 index 000000000..959e8a74e --- /dev/null +++ b/transcripts/fix-C009-attempt2.jsonl @@ -0,0 +1,144 @@ +{"ts": 1778573002.6004434, "type": "system"} +{"ts": 1778573009.7817116, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me analyze the failing test and understand what's going wrong. The error message is:\n\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n```\n\nThe error is about \"Invalid combination of auth properties\" for a datasource \"demo-test-ds\". \n\nThe problem is occurring in `put_declarative_ip_allowlist_policies` when it calls `set_organization_layout` - the read-modify-write pattern is causing issues because when the full org layout gets read back and written, it's attempting to PUT the datasource with incomplete auth credentials. There's also an earlier error about missing 'users' entities that don't exist in the system, so I need to look at the test to understand what's actually being set up and what's failing.", "truncated": false}]} +{"ts": 1778573009.7887871, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01MfLEAbbFzMcBQDtZmcebJt", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 570, \"limit\": 80}", "truncated": false}]} +{"ts": 1778573009.8037243, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MfLEAbbFzMcBQDtZmcebJt", "is_error": false, "content": "570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"group.admins\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"employee123\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"group.admins\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"employee123\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} +{"ts": 1778573009.8042865, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_013ujfxuSCcMVHqYNdyzqfr3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 50}", "truncated": false}]} +{"ts": 1778573009.825166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_013ujfxuSCcMVHqYNdyzqfr3", "is_error": false, "content": "750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} +{"ts": 1778573018.1809082, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The error is:\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n```\n\nThe problem is clear now: when reading the org layout and writing it back, the org layout contains datasources (like \"demo-test-ds\") that have auth credentials that are not fully present in the GET response (passwords are typically masked/omitted). \n\nWhen the full layout is PUT back, the server rejects it because the auth credentials are incomplete. This is a known issue with read-modify-write approaches on layouts containing sensitive data\u2014the GET response masks passwords, so when I PUT it back, the server sees an invalid combination of auth properties.\n\nI need to explore whether there's a dedicated endpoint for updating just the IP allowlist policies, or if I should handle the read-modify-write differently to preserve the original auth configuration without modifying it.", "truncated": false}]} +{"ts": 1778573018.2852287, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Ds7ARTM2d17ctngauHF74k", "input": "{\"pattern\": \"ip_allowlist\\\\|ipAllowlist\\\\|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778573018.667458, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ds7ARTM2d17ctngauHF74k", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778573018.763352, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018NrTrPzyxbw7AFkBC9LpcN", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py\"}", "truncated": false}]} +{"ts": 1778573018.8059125, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018NrTrPzyxbw7AFkBC9LpcN", "is_error": false, "content": "1\t# (C) 2025 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\t\n6\tfrom attrs import define, field\n7\tfrom gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n8\t\n9\tfrom gooddata_sdk.catalog.base import Base\n10\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n11\t\n12\t\n13\t@define(kw_only=True)\n14\tclass CatalogDeclarativeIpAllowlistPolicy(Base):\n15\t id: str\n16\t allowed_sources: list[str] = field(factory=list)\n17\t user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list)\n18\t users: list[CatalogUserIdentifier] = field(factory=list)\n19\t\n20\t @staticmethod\n21\t def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]:\n22\t return DeclarativeIpAllowlistPolicy\n23\t", "truncated": false}]} +{"ts": 1778573021.950166, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the `ip_allowlist` endpoint doesn't exist in the layout_api at all. The error is because of the read-modify-write approach: when the full org layout is read and PUT back, datasources with incomplete auth credentials (password was masked in the GET response) fail.\n\nLet me look at how the other layout methods handle this, and see if there's a dedicated endpoint in the layout_api we can use.", "truncated": false}]} +{"ts": 1778573022.344003, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_0121fLDBNLgsyYTuPgGcftbK", "input": "{\"command\": \"grep -n \\\"ip_allowlist\\\\|IpAllowlist\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py | head -40\"}", "truncated": false}]} +{"ts": 1778573022.7280967, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0121fLDBNLgsyYTuPgGcftbK", "is_error": true, "content": "Blocked: grep -n \"ip_allowlist\\|IpAllowlist\" /home/runner/_work/gdc-nas/gdc-nas/sdk/goodd", "truncated": false}]} +{"ts": 1778573022.9883952, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_017swQLmfmA1qH6BEpHyGC4Y", "input": "{\"command\": \"grep -n \\\"def get_\\\\|def set_\\\\|def put_\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py | head -60\"}", "truncated": false}]} +{"ts": 1778573023.0247822, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017swQLmfmA1qH6BEpHyGC4Y", "is_error": true, "content": "Blocked: grep -n \"def get_\\|def set_\\|def put_\" /home/runner/_work/gdc-nas/gdc-nas/sdk/go", "truncated": false}]} +{"ts": 1778573025.3225725, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01QDBkX5LqxqVUNJ8BpkNmQ2", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778573025.714029, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QDBkX5LqxqVUNJ8BpkNmQ2", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778573026.0078123, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01SHZ7ff5io71ZKh5sc9qVpY", "input": "{\"pattern\": \"def (get|set|put)_\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 80}", "truncated": false}]} +{"ts": 1778573026.0414166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01SHZ7ff5io71ZKh5sc9qVpY", "is_error": false, "content": "2578: def get_agents_layout(\n2656: def get_analytics_model(\n2740: def get_automations(\n2824: def get_custom_geo_collections_layout(\n2902: def get_data_source_permissions(\n2985: def get_data_source_statistics(\n3070: def get_data_sources_layout(\n3148: def get_export_templates_layout(\n3226: def get_filter_views(\n3310: def get_identity_providers_layout(\n3388: def get_logical_model(\n3472: def get_notification_channels_layout(\n3550: def get_organization_layout(\n3629: def get_organization_permissions(\n3707: def get_user_data_filters(\n3790: def get_user_group_permissions(\n3873: def get_user_groups_layout(\n3951: def get_user_permissions(\n4034: def get_users_layout(\n4112: def get_users_user_groups_layout(\n4190: def get_workspace_data_filters_layout(\n4268: def get_workspace_layout(\n4352: def get_workspace_permissions(\n4435: def get_workspaces_layout(\n4514: def put_data_source_statistics(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5103: def set_analytics_model(\n5190: def set_automations(\n5277: def set_custom_geo_collections(\n5360: def set_data_source_permissions(\n5447: def set_export_templates(\n5530: def set_filter_views(\n5617: def set_identity_providers(\n5700: def set_logical_model(\n5787: def set_notification_channels(\n5870: def set_organization_layout(\n5953: def set_organization_permissions(\n6036: def set_user_data_filters(\n6123: def set_user_group_permissions(\n6210: def set_user_permissions(\n6297: def set_workspace_data_filters_layout(\n6380: def set_workspace_permissions(\n6467: def set_workspaces_layout(", "truncated": false}]} +{"ts": 1778573035.8089197, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no dedicated `get_ip_allowlist` or `set_ip_allowlist` method. The only way to manage IP allowlist policies is through the full organization layout (get/set_organization_layout).\n\nThe error message is:\n```\n{\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n\n\n```\n\nThe issue is that when I fetch the organization layout via GET, sensitive credentials like datasource passwords are masked or stripped from the response. When I PUT that incomplete layout back, the server rejects it because it sees `user: yes, password: no` which is an invalid auth combination. This read-modify-write pattern doesn't work for `set_organization_layout` because the GET response is already redacted. I need to look at how other tests handle organization layout operations to find a workaround.\n\n```", "truncated": false}]} +{"ts": 1778573036.0690591, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Vww37Xwt3GjoCUWxgnxxsv", "input": "{\"pattern\": \"set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778573036.0799193, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Vww37Xwt3GjoCUWxgnxxsv", "is_error": false, "content": "777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778573036.1039321, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01E8At1vhYvKtHrkwwNnwPUi", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778573036.1452413, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01E8At1vhYvKtHrkwwNnwPUi", "is_error": false, "content": "756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778573038.750805, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The key issue is: when reading the org layout with GET, datasource passwords are masked. When PUT-ting back, the server rejects it because the datasource has a user but no password.\n\nLet me look at the full `put_declarative_organization_layout` method and see how it handles this:", "truncated": false}]} +{"ts": 1778573039.527552, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HZa9BuT5WSL9y7JN6n9QqQ", "input": "{\"pattern\": \"put_declarative_organization|get_declarative_organization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778573039.910496, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HZa9BuT5WSL9y7JN6n9QqQ", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778573040.2416205, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_0114KpWHD9cSL8P6RMfJbApU", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} +{"ts": 1778573040.277885, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0114KpWHD9cSL8P6RMfJbApU", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport functools\n5\tfrom typing import Any, Literal\n6\t\n7\tfrom gooddata_api_client.exceptions import NotFoundException\n8\tfrom gooddata_api_client.model.declarative_export_templates import DeclarativeExportTemplates\n9\tfrom gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n10\tfrom gooddata_api_client.model.json_api_csp_directive_in_document import JsonApiCspDirectiveInDocument\n11\tfrom gooddata_api_client.model.json_api_export_template_in_document import JsonApiExportTemplateInDocument\n12\tfrom gooddata_api_client.model.json_api_export_template_post_optional_id_document import (\n13\t JsonApiExportTemplatePostOptionalIdDocument,\n14\t)\n15\tfrom gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument\n16\tfrom gooddata_api_client.model.json_api_organization_patch import JsonApiOrganizationPatch\n17\tfrom gooddata_api_client.model.json_api_organization_patch_document import JsonApiOrganizationPatchDocument\n18\tfrom gooddata_api_client.model.json_api_organization_setting_in_document import JsonApiOrganizationSettingInDocument\n19\tfrom gooddata_api_client.model.switch_identity_provider_request import SwitchIdentityProviderRequest\n20\t\n21\tfrom gooddata_sdk import CatalogDeclarativeExportTemplate, CatalogExportTemplate\n22\tfrom gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase\n23\tfrom gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective\n24\tfrom gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider\n25\tfrom gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument\n26\tfrom gooddata_sdk.catalog.organization.entity_model.llm_provider import (\n27\t CatalogLlmProvider,\n28\t CatalogLlmProviderDocument,\n29\t CatalogLlmProviderPatch,\n30\t CatalogLlmProviderPatchDocument,\n31\t)\n32\tfrom gooddata_sdk.c", "truncated": true}]} +{"ts": 1778573042.9638257, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Rk2jXe2PtbxBNkdAAapfgb", "input": "{\"pattern\": \"set_notification_channels|notification_channel|set_identity_providers\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} +{"ts": 1778573042.9979026, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Rk2jXe2PtbxBNkdAAapfgb", "is_error": false, "content": "9:from gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n35:from gooddata_sdk.catalog.organization.layout.notification_channel import CatalogDeclarativeNotificationChannel\n634: def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:\n644: for nc in self._layout_api.get_notification_channels_layout().notification_channels\n647: def put_declarative_notification_channels(\n648: self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n654: notification_channels (list[CatalogDeclarativeNotificationChannel]):\n660: api_ncs = [nc.to_api() for nc in notification_channels]\n661: self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n687: self._layout_api.set_identity_providers(declarative_identity_provider=api_idps)", "truncated": false}]} +{"ts": 1778573047.4959223, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! For notification channels, they use `get_notification_channels_layout()` and `set_notification_channels()` - there are dedicated endpoints for these. Similarly for identity providers.\n\nBut the IP allowlist policies don't have dedicated endpoints - they only appear in the full org layout.\n\nHowever, the error shows that when we PUT back the full org layout, the server rejects it because of datasource authentication issues. The datasources have their passwords masked in the GET response, so when we PUT back, it fails validation.\n\nLet me look at how the full organization layout get/put is done in the existing tests to understand how others handle this.", "truncated": false}]} +{"ts": 1778573048.3063338, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0116G7Xr4zQggtTFJB9qNxTJ", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} +{"ts": 1778573048.7013912, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0116G7Xr4zQggtTFJB9qNxTJ", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778573048.7433405, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Dk3xeZz9yxqjguNV72joe9", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778573048.7775166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Dk3xeZz9yxqjguNV72joe9", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778573053.7536654, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So `set_organization_layout` is only used in the new IP allowlist policy code. No other method uses it directly. \n\nThe error is that when reading the full org layout and writing it back, the datasource password is masked (not returned), so the PUT fails because the datasource has a user but no password.\n\nLet me check what the DeclarativeOrganization model looks like and if there's a way to avoid sending data sources in the PUT.\n\nActually, looking at this more carefully - I need to understand what's happening. The full organization layout includes data sources with masked passwords. When we PUT it back, the server rejects it.\n \nNow I'm examining the DeclarativeOrganization schema to see what fields are available.", "truncated": false}]} +{"ts": 1778573053.7607636, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_016Mxx1rwS8arUEYn2zq7EuT", "input": "{\"pattern\": \"**/declarative_organization.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client\"}", "truncated": false}]} +{"ts": 1778573053.7900732, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016Mxx1rwS8arUEYn2zq7EuT", "is_error": false, "content": "gooddata-api-client/build/lib/gooddata_api_client/model/declarative_organization.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py", "truncated": false}]} +{"ts": 1778573055.8554795, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Y7LKeNsUNx2GS2h3t592SH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"limit\": 80}", "truncated": false}]} +{"ts": 1778573055.8892395, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Y7LKeNsUNx2GS2h3t592SH", "is_error": false, "content": "1\t\"\"\"\n2\t OpenAPI definition\n3\t\n4\t No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501\n5\t\n6\t The version of the OpenAPI document: v0\n7\t Contact: support@gooddata.com\n8\t Generated by: https://openapi-generator.tech\n9\t\"\"\"\n10\t\n11\t\n12\timport re # noqa: F401\n13\timport sys # noqa: F401\n14\t\n15\tfrom gooddata_api_client.model_utils import ( # noqa: F401\n16\t ApiTypeError,\n17\t ModelComposed,\n18\t ModelNormal,\n19\t ModelSimple,\n20\t cached_property,\n21\t change_keys_js_to_python,\n22\t convert_js_args_to_python_args,\n23\t date,\n24\t datetime,\n25\t file_type,\n26\t none_type,\n27\t validate_get_composed_info,\n28\t OpenApiModel\n29\t)\n30\tfrom gooddata_api_client.exceptions import ApiAttributeError\n31\t\n32\t\n33\tdef lazy_import():\n34\t from gooddata_api_client.model.declarative_agent import DeclarativeAgent\n35\t from gooddata_api_client.model.declarative_custom_geo_collection import DeclarativeCustomGeoCollection\n36\t from gooddata_api_client.model.declarative_data_source import DeclarativeDataSource\n37\t from gooddata_api_client.model.declarative_export_template import DeclarativeExportTemplate\n38\t from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider\n39\t from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n40\t from gooddata_api_client.model.declarative_jwk import DeclarativeJwk\n41\t from gooddata_api_client.model.declarative_notification_channel import DeclarativeNotificationChannel\n42\t from gooddata_api_client.model.declarative_organization_info import DeclarativeOrganizationInfo\n43\t from gooddata_api_client.model.declarative_user import DeclarativeUser\n44\t from gooddata_api_client.model.declarative_user_group import DeclarativeUserGroup\n45\t from gooddata_api_client.model.declarative_workspace import DeclarativeWorkspace\n46\t from gooddata_api_client.mode", "truncated": true}]} +{"ts": 1778573057.8807747, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01S3ZEduRGisoB9SeUKrTadH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 80, \"limit\": 120}", "truncated": false}]} +{"ts": 1778573057.9238005, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01S3ZEduRGisoB9SeUKrTadH", "is_error": false, "content": "80\t min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,\n81\t inclusive_minimum, and regex.\n82\t additional_properties_type (tuple): A tuple of classes accepted\n83\t as additional properties values.\n84\t \"\"\"\n85\t\n86\t allowed_values = {\n87\t }\n88\t\n89\t validations = {\n90\t }\n91\t\n92\t @cached_property\n93\t def additional_properties_type():\n94\t \"\"\"\n95\t This must be a method because a model may have properties that are\n96\t of type self, this must run after the class is loaded\n97\t \"\"\"\n98\t lazy_import()\n99\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n100\t\n101\t _nullable = False\n102\t\n103\t @cached_property\n104\t def openapi_types():\n105\t \"\"\"\n106\t This must be a method because a model may have properties that are\n107\t of type self, this must run after the class is loaded\n108\t\n109\t Returns\n110\t openapi_types (dict): The key is attribute name\n111\t and the value is attribute type.\n112\t \"\"\"\n113\t lazy_import()\n114\t return {\n115\t 'organization': (DeclarativeOrganizationInfo,), # noqa: E501\n116\t 'agents': ([DeclarativeAgent],), # noqa: E501\n117\t 'custom_geo_collections': ([DeclarativeCustomGeoCollection],), # noqa: E501\n118\t 'data_sources': ([DeclarativeDataSource],), # noqa: E501\n119\t 'export_templates': ([DeclarativeExportTemplate],), # noqa: E501\n120\t 'identity_providers': ([DeclarativeIdentityProvider],), # noqa: E501\n121\t 'ip_allowlist_policies': ([DeclarativeIpAllowlistPolicy],), # noqa: E501\n122\t 'jwks': ([DeclarativeJwk],), # noqa: E501\n123\t 'notification_channels': ([DeclarativeNotificationChannel],), # noqa: E501\n124\t 'user_groups': ([DeclarativeUserGroup],), # noqa: E501\n125\t 'users': ([DeclarativeUser],), # noqa: E501\n12", "truncated": true}]} +{"ts": 1778573073.5983717, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the full picture. The `DeclarativeOrganization` schema includes `data_sources` which have auth properties. When we GET the organization layout, the passwords are masked/null. When we PUT it back, the server rejects it because of the incomplete datasource credentials.\n\nThe fundamental issue is that the read-modify-write approach for the full org layout is broken because:\n1. GET returns org layout with masked datasource passwords\n2. PUT with the masked passwords fails validation\n\nThe real question is: how can we update just the `ip_allowlist_policies` field without breaking the datasource auth?\n\nLooking at the approach, there are a few options:\n\n\n1. Remove the `data_sources` field from the org layout before PUTting back \n2. Find another way to only update the ip_allowlist_policies\n\nLet me check whether `set_organization_layout` actually validates datasource auth properties. Looking at the error, it's clear the server is rejecting the datasource because it has a username but no password, which violates the auth validation rules.\n\nThe real issue is that when the org layout is fetched, the password field gets masked or stripped out. When I PUT it back with just the username, the server rejects it as an invalid auth combination. I'm weighing my options: stripping the `data_sources` field entirely risks deleting them, and setting it to an empty list has the same problem. The safest approach might be to omit the `data_sources` key from the PUT request entirely, but I need to understand whether the API treats missing fields as \"don't change\" or \"delete.\"\n\nLooking at the test setup, it's using a VCR cassette called `layout_ip_allowlist_policies.yaml` to mock the API responses, so the test shouldn't be hitting a live server. Let me check if that cassette file actually exists and what it contains.", "truncated": false}]} +{"ts": 1778573073.600673, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01AmXqhpub2r5EcSnECRmdTK", "input": "{\"pattern\": \"**/layout_ip_allowlist_policies.yaml\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778573073.6162353, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Cq1AfKfQbdozfcRigD8247", "input": "{\"pattern\": \"**/_fixtures_dir*\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog\"}", "truncated": false}]} +{"ts": 1778573073.6409242, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01AmXqhpub2r5EcSnECRmdTK", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml", "truncated": false}]} +{"ts": 1778573073.6414046, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Cq1AfKfQbdozfcRigD8247", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778573085.192074, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette exists. Let me check the cassette file to understand what's happening.\n\nWait - the test output shows that the test is actually hitting the live server and getting a real 400 error. Let me re-read the failing test output more carefully:\n\n```\nDuring handling of the above exception, another exception occurred:\ntests/catalog/test_catalog_organization.py:600: in test_layout_ip_allowlist_policies\n sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n```\n\nSo the first exception happened in the `try` block (but we don't see it in the output). \n\nThe second exception happens in the `finally` block when trying to restore `original_policies`. The test flow is: GET original policies succeeds, PUT new policies fails because the referenced user doesn't exist, then in the finally block the restore also fails with a datasource auth issue.\n\nLooking more carefully at the traceback, the actual failure is from the restore call itself\u2014when `put_declarative_ip_allowlist_policies` reads back the full org layout and tries to PUT it, the layout contains datasources with masked passwords that cause the auth validation to fail.\n\nThe cassette file should have the recorded responses, but I need to verify it has the right data for this scenario.", "truncated": false}]} +{"ts": 1778573085.201973, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_011A9ZdRCuyZTLpMNaA25cg2", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} +{"ts": 1778573085.2296975, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011A9ZdRCuyZTLpMNaA25cg2", "is_error": true, "content": "File content (927KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.", "truncated": false}]} +{"ts": 1778573093.9674752, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette file is 927KB! It has a full set of responses. Let me check if the test is actually using the cassette or hitting a live server. Since the cassette exists and has content, it must be a recorded cassette. But then why is it failing with a real HTTP 400 error?\n\nWait - looking at the error output again:\n```\nE HTTP response headers: Content-Length: 330\nE Expires: 0\nE X-Content-Type-Options: nosniff\n...\nE Date: Tue, 12 May 2026 08:03:18 GMT\n\n\n```\n\nThis has a real date (2026-05-12, today's date), and the response headers look real. This means the test is NOT using the cassette or the cassette doesn't have the right responses. Let me reconsider the ground rules about not fabricating cassette files since they'll be re-recorded anyway. The cassette exists at `packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml` and is 927KB, but I need to verify if it actually contains valid VCR responses for this test.\n\n```", "truncated": false}]} +{"ts": 1778573093.9778664, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DTZLDzdKQc2dYnL41C8hKw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} +{"ts": 1778573094.0081472, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DTZLDzdKQc2dYnL41C8hKw", "is_error": false, "content": "1\tinteractions:\n2\t - request:\n3\t body: null\n4\t headers:\n5\t Accept:\n6\t - application/json\n7\t Accept-Encoding:\n8\t - br, gzip, deflate\n9\t X-GDC-VALIDATE-RELATIONS:\n10\t - 'true'\n11\t X-Requested-With:\n12\t - XMLHttpRequest\n13\t method: GET\n14\t uri: http://localhost:3000/api/v1/layout/organization\n15\t response:\n16\t body:\n17\t string:\n18\t agents:\n19\t - aiKnowledge: true\n20\t availableToAll: true\n21\t enabled: true\n22\t id: default-ai-assistant\n23\t name: Default GoodData AI Assistant\n24\t skillsMode: all\n25\t customGeoCollections: []\n26\t dataSources:\n27\t - alternativeDataSourceId: ds-put-abc-id\n28\t authenticationType: USERNAME_PASSWORD\n29\t id: demo-test-ds\n30\t name: demo-test-ds\n31\t permissions:\n32\t - assignee:\n33\t id: demo2\n34\t type: user\n35\t name: MANAGE\n36\t - assignee:\n37\t id: demoGroup\n38\t type: userGroup\n39\t name: USE\n40\t schema: demo\n41\t type: POSTGRESQL\n42\t url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\n43\t username: postgres\n44\t exportTemplates: []\n45\t identityProviders:\n46\t - id: defaultIdp\n47\t idpType: DEX_IDP\n48\t ipAllowlistPolicies: []\n49\t jwks: []\n50\t notificationChannels: []", "truncated": false}]} +{"ts": 1778573097.3050752, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I can see the structure! The cassette has a GET response for the org layout. Notice it doesn't have the `password` field in the datasource. This is the masked response.\n\nNow I need to check what happens with the PUT responses. Let me look further in the cassette file to find the PUT requests.", "truncated": false}]} +{"ts": 1778573098.0720143, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01WdSsvmFVsxz9aCiKZNWern", "input": "{\"pattern\": \"method: PUT|status:|400\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778573098.1046343, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WdSsvmFVsxz9aCiKZNWern", "is_error": false, "content": "2144: status:\n4288: status:\n6425: method: PUT\n6432: status: 400\n6446: status:\n6447: code: 400\n8590: status:\n10717: method: PUT\n10726: status: 400\n10740: status:\n10741: code: 400\n12884: status:\n15028: status:\n17165: method: PUT\n17172: status: 400\n17186: status:\n17187: code: 400\n19330: status:\n21457: method: PUT\n21466: status: 400\n21480: status:\n21481: code: 400", "truncated": false}]} +{"ts": 1778573101.485494, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There are multiple PUT requests in the cassette, and they all return status 400! This is the problem. The cassette has recorded the 400 errors. The PUTs return 400 in the cassette itself.\n\nLet me look at what the cassette PUT requests contain and what the 400 responses say.", "truncated": false}]} +{"ts": 1778573102.0067546, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01LPfSaeeqzH776wBPo8unWw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6420, \"limit\": 60}", "truncated": false}]} +{"ts": 1778573102.0504959, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LPfSaeeqzH776wBPo8unWw", "is_error": false, "content": "6420\t - application/json\n6421\t X-GDC-VALIDATE-RELATIONS:\n6422\t - 'true'\n6423\t X-Requested-With:\n6424\t - XMLHttpRequest\n6425\t method: PUT\n6426\t uri: http://localhost:3000/api/v1/layout/organization\n6427\t response:\n6428\t body:\n6429\t string:\n6430\t detail: 'Some of given referenced ''users'' entities do not exist. Not existing\n6431\t IDs: [Identifier(employee123)/Organization(default)]'\n6432\t status: 400\n6433\t title: Bad Request\n6434\t traceId: NORMALIZED_TRACE_ID_000000000000\n6435\t headers:\n6436\t Content-Type:\n6437\t - application/problem+json\n6438\t DATE: *id001\n6439\t Expires:\n6440\t - '0'\n6441\t Pragma:\n6442\t - no-cache\n6443\t X-Content-Type-Options:\n6444\t - nosniff\n6445\t X-GDC-TRACE-ID: *id001\n6446\t status:\n6447\t code: 400\n6448\t message: Bad Request\n6449\t - request:\n6450\t body: null\n6451\t headers:\n6452\t Accept:\n6453\t - application/json\n6454\t Accept-Encoding:\n6455\t - br, gzip, deflate\n6456\t X-GDC-VALIDATE-RELATIONS:\n6457\t - 'true'\n6458\t X-Requested-With:\n6459\t - XMLHttpRequest\n6460\t method: GET\n6461\t uri: http://localhost:3000/api/v1/layout/organization\n6462\t response:\n6463\t body:\n6464\t string:\n6465\t agents:\n6466\t - aiKnowledge: true\n6467\t availableToAll: true\n6468\t enabled: true\n6469\t id: default-ai-assistant\n6470\t name: Default GoodData AI Assistant\n6471\t skillsMode: all\n6472\t customGeoCollections: []\n6473\t dataSources:\n6474\t - alternativeDataSourceId: ds-put-abc-id\n6475\t authenticationType: USERNAME_PASSWORD\n6476\t id: demo-test-ds\n6477\t name: demo-test-ds\n6478\t permissions:\n6479\t - as", "truncated": true}]} +{"ts": 1778573108.6583698, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern. In the cassette:\n\n1. The first PUT (with new_policies that includes employee123 user) returns 400 with \"users entities do not exist: employee123\" - this is expected and is within the `try` block. The `put_declarative_ip_allowlist_policies` doesn't catch this, so the exception propagates out of the try block and into the finally block.\n\n2. In the finally block, it calls `put_declarative_ip_allowlist_policies(original_policies)` which:\n a. GETs the org layout \n b. PUTs the org layout back with the original empty `ip_allowlist_policies`\n \n3. But the PUT in step 2b also returns 400 in the cassette! This is strange - I need to check if the subsequent PUTs are also hitting the datasource auth error, so let me look at what's happening at line 10717 where the second PUT occurs.", "truncated": false}]} +{"ts": 1778573108.676665, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01RwKM9sFfiE1Qxt25H1gWV6", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 10710, \"limit\": 50}", "truncated": false}]} +{"ts": 1778573108.7103844, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01RwKM9sFfiE1Qxt25H1gWV6", "is_error": false, "content": "10710\t - br, gzip, deflate\n10711\t Content-Type:\n10712\t - application/json\n10713\t X-GDC-VALIDATE-RELATIONS:\n10714\t - 'true'\n10715\t X-Requested-With:\n10716\t - XMLHttpRequest\n10717\t method: PUT\n10718\t uri: http://localhost:3000/api/v1/layout/organization\n10719\t response:\n10720\t body:\n10721\t string:\n10722\t detail: 'Invalid combination of auth properties. Only none, user + password,\n10723\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n10724\t user: , password: , token: , key-pair: , clientId: ,\n10725\t clientSecret: '\n10726\t status: 400\n10727\t title: Bad Request\n10728\t traceId: NORMALIZED_TRACE_ID_000000000000\n10729\t headers:\n10730\t Content-Type:\n10731\t - application/problem+json\n10732\t DATE: *id001\n10733\t Expires:\n10734\t - '0'\n10735\t Pragma:\n10736\t - no-cache\n10737\t X-Content-Type-Options:\n10738\t - nosniff\n10739\t X-GDC-TRACE-ID: *id001\n10740\t status:\n10741\t code: 400\n10742\t message: Bad Request\n10743\t - request:\n10744\t body: null\n10745\t headers:\n10746\t Accept:\n10747\t - application/json\n10748\t Accept-Encoding:\n10749\t - br, gzip, deflate\n10750\t X-GDC-VALIDATE-RELATIONS:\n10751\t - 'true'\n10752\t X-Requested-With:\n10753\t - XMLHttpRequest\n10754\t method: GET\n10755\t uri: http://localhost:3000/api/v1/layout/organization\n10756\t response:\n10757\t body:\n10758\t string:\n10759\t agents:", "truncated": false}]} +{"ts": 1778573135.6066444, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I can clearly see the problem! The cassette records the PUT responses as 400 errors. This is because the cassette was recorded when the PUTs were actually failing (the test was failing when the cassette was created).\n\nThe fundamental issue is: when the full org layout is read and PUT back, the datasource has `username: postgres` but no password field (it's masked). The server rejects this as \"Invalid combination of auth properties\".\n\nThe fix options are:\n1. **Don't use read-modify-write for set_organization_layout** - find another endpoint or approach\n2. **Before PUT, remove the `data_sources` field or set it to not include auth info** - risky, might delete datasources\n\n\n3. **Use a different endpoint** - but there's no dedicated one for IP allowlist policies\n\nI'm realizing the cassette might have been recorded with these failures already baked in, which is odd. Let me reconsider whether this cassette was actually created fresh or if it's a stale one that wasn't properly cleaned up. The test flow depends on understanding what the cassette actually contains and whether it's meant to show success or failure.\n\nLooking at the cassette structure, I can see there are four PUT requests all returning 400 errors. The first one fails with \"users entities do not exist: employee123\" when trying to put the new policies, and the second fails with \"Invalid combination of auth properties\" when attempting to restore the original policies in the finally block. This tells me the test was already failing when the cassette was recorded.\n\nThe root issue appears to be in how `put_declarative_ip_allowlist_policies` handles the full org layout - when it reads and PUTs back the configuration, the datasource password gets stripped out, triggering that 400 error. I need to figure out how to prevent this auth stripping when restoring the policies.\n\nI'm also noticing the conftest warning about detecting test failures and restoring a session snapshot, which might be triggering additional PUT c", "truncated": true}]} +{"ts": 1778573135.6167443, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NX7Cjwdks51bb6ZcNTH6aH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 5870, \"limit\": 100}", "truncated": false}]} +{"ts": 1778573135.6479452, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NX7Cjwdks51bb6ZcNTH6aH", "is_error": false, "content": "5870\t def set_organization_layout(\n5871\t self,\n5872\t declarative_organization,\n5873\t **kwargs\n5874\t ):\n5875\t \"\"\"Set organization layout # noqa: E501\n5876\t\n5877\t Sets complete layout of organization, like workspaces, user-groups, etc. # noqa: E501\n5878\t This method makes a synchronous HTTP request by default. To make an\n5879\t asynchronous HTTP request, please pass async_req=True\n5880\t\n5881\t >>> thread = api.set_organization_layout(declarative_organization, async_req=True)\n5882\t >>> result = thread.get()\n5883\t\n5884\t Args:\n5885\t declarative_organization (DeclarativeOrganization):\n5886\t\n5887\t Keyword Args:\n5888\t _return_http_data_only (bool): response data without head status\n5889\t code and headers. Default is True.\n5890\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n5891\t will be returned without reading/decoding response data.\n5892\t Default is True.\n5893\t _request_timeout (int/float/tuple): timeout setting for this request. If\n5894\t one number provided, it will be total request timeout. It can also\n5895\t be a pair (tuple) of (connection, read) timeouts.\n5896\t Default is None.\n5897\t _check_input_type (bool): specifies if type checking\n5898\t should be done one the data sent to the server.\n5899\t Default is True.\n5900\t _check_return_type (bool): specifies if type checking\n5901\t should be done one the data received from the server.\n5902\t Default is True.\n5903\t _spec_property_naming (bool): True if the variable names in the input data\n5904\t are serialized names, as specified in the OpenAPI document.\n5905\t False if the variable names in the input data\n5906\t are pythonic names, e.g. snake case (default)\n5", "truncated": true}]} +{"ts": 1778573286.6969438, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The API documentation says `set_organization_layout` \"Sets complete layout of organization\". This means it's a complete replacement - any field not included might be cleared/deleted.\n\nLet me look at how the cassette was structured again more carefully. The cassette has failures recorded. The test is failing because the cassette has 400 errors. \n\nThe key question is: should I:\n1. Fix the code to avoid the 400 error AND delete the cassette so it gets re-recorded\n2. Or fix the cassette manually\n\nGiven that the task description says \"Do NOT fabricate cassette YAML files \u2014 they will be re-recorded by the pipeline after you finish. \n\nOption 1 is the right approach - delete the problematic cassette and fix the code. The instruction about stale cassettes being already deleted suggests I should remove this one too since it contains baked-in failures. The pipeline has a mechanism to re-record cassettes, so deleting it and fixing the underlying code issue is the way forward.\n\nLooking at the test flow more carefully, the real problem is that steps 2 and 4 both fail when trying to PUT the org layout back - the full layout includes a datasource with a postgres username but no password, which the API rejects. I need to either fix the code to avoid the read-modify-write pattern on the full org layout or handle the datasource issue properly. because of datasource auth. That's expected. But step 4 also fails because of datasource auth. Actually step 4 is the `put_declarative_ip_allowlist_policies(original_policies)` call in the finally block.\n\nWait, looking at the flow again:\n- `put_declarative_ip_allowlist_policies(new_policies)`: GETs org layout, sets ip_allowlist_policies=new, PUTs org layout back\n - This fails with 400: users entities do not exist (employee123)\n - This is expected, it's in a try block\n- In the finally block: `put_declarative_ip_allowlist_policies(original_policies)`: GETs org layout, sets ip_allowlist_policies=original (empty []), PUTs org layout back\n - This ", "truncated": true}]} +{"ts": 1778573286.6970382, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the cassette for more context:", "truncated": false}]} +{"ts": 1778573286.6972933, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01ArxeCFzZ1cRGVhoUwP1YAY", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 50, \"limit\": 120}", "truncated": false}]} +{"ts": 1778573286.7171073, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01ArxeCFzZ1cRGVhoUwP1YAY", "is_error": false, "content": "50\t notificationChannels: []\n51\t organization:\n52\t allowedOrigins: []\n53\t colorPalettes: []\n54\t cspDirectives: []\n55\t earlyAccess: enableAlerting\n56\t earlyAccessValues:\n57\t - enableAlerting\n58\t - enableSmtp\n59\t - enablePreAggregationDatasets\n60\t - enableScheduling\n61\t - enableCompositeGrain\n62\t - enableUserManagement\n63\t - enableRawExports\n64\t - enableFlexibleDashboardLayout\n65\t hostname: localhost\n66\t id: default\n67\t identityProvider:\n68\t id: defaultIdp\n69\t type: identityProvider\n70\t name: Default Organization\n71\t permissions:\n72\t - assignee:\n73\t id: adminGroup\n74\t type: userGroup\n75\t name: MANAGE\n76\t settings: []\n77\t themes: []\n78\t userGroups:\n79\t - id: adminGroup\n80\t permissions: []\n81\t - id: adminQA1Group\n82\t parents:\n83\t - id: adminGroup\n84\t type: userGroup\n85\t permissions: []\n86\t - id: demoGroup\n87\t name: demo group\n88\t permissions: []\n89\t - id: visitorsGroup\n90\t name: visitors\n91\t parents:\n92\t - id: demoGroup\n93\t type: userGroup\n94\t permissions: []\n95\t users:\n96\t - id: admin\n97\t permissions: []\n98\t settings: []\n99\t userGroups:\n100\t - id: adminGroup\n101\t type: userGroup\n102\t - authId: NORMALIZED_AUTH_ID\n103\t email: demo@example.com\n104\t firstname: Demo\n105\t id: demo\n106\t lastname: User\n107\t permissions: []\n108\t settings: []\n109\t ", "truncated": true}]} +{"ts": 1778573328.3716877, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the cassette, the org has `id: default`, not `python-sdk-dex`. And the users in the cassette are `admin`, `demo`, `demo2`. There's no `employee123` user. So the cassette was recorded against a different environment.\n\nBut the cassette DOES have the PUT failures (400 errors). This is interesting. The cassette must have been recorded with the failing PUTs. Why?\n\nActually - wait. I just realized something. The cassette might have been created by the prior agent specifically to capture the test behavior - BUT the test was already failing when the cassette was created. So the cassette faithfully records the failure.\n \nSo the real question is whether the live server would have the same issues. The test would fail on a live staging instance because `employee123` doesn't exist and the datasource auth would block the PUT calls. If the cassette gets deleted, the test needs both of those problems fixed to pass against the actual server.\n\nLooking at the test data more carefully, I need to understand what user groups are being referenced and whether they're valid in the staging environment. I need to swap out the test data to use users and groups that actually exist in the test environment \u2014 `demo2` instead of `employee123`, and `demoGroup` instead of `group.admins`. That should let the PUT request succeed once I also fix the datasource authentication issue. The full solution involves updating the test data, handling incomplete datasource auth in the `put_declarative_ip_allowlist_policies` method, and removing the stale cassette. Now I'm trying to figure out how to address the datasource auth problem.\n\nWhen the org layout GET returns, it includes a datasource with a username but no password, and the server rejects it on PUT. I could either clear the `data_sources` field entirely before sending it back, or remove that attribute from the object so it doesn't get serialized. Let me explore how ModelNormal handles attribute deletion and whether removing the field would pre", "truncated": true}]} +{"ts": 1778573328.3805187, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest and VCR setup:", "truncated": false}]} +{"ts": 1778573328.3809576, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01ChPNobiRCwF2tywXHyUAfD", "input": "{\"pattern\": \"gd_vcr|vcrpy|use_cassette|record_mode\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 40}", "truncated": false}]} +{"ts": 1778573328.6417518, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01ChPNobiRCwF2tywXHyUAfD", "is_error": false, "content": "packages/gooddata-sdk/tests/table/test_table.py:9:from tests_support.vcrpy_utils import get_vcr\npackages/gooddata-sdk/tests/table/test_table.py:11:gd_vcr = get_vcr()\npackages/gooddata-sdk/tests/table/test_table.py:28:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_just_attribute.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:38:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_just_metric.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:52:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_and_metric.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:67:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_metric_and_filter.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:83:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_show_all_values.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:9:from tests_support.vcrpy_utils import get_vcr\npackages/gooddata-sdk/tests/support/test_support.py:11:gd_vcr = get_vcr()\npackages/gooddata-sdk/tests/support/test_support.py:17:@gd_vcr.use_cassette(str(_fixtures_dir / \"is_available.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:28:@gd_vcr.use_cassette(str(_fixtures_dir / \"is_available_no_access.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:35:@gd_vcr.use_cassette(str(_fixtures_dir / \"wait_till_available_no_wait.yaml\"))\npackages/gooddata-sdk/tests/overview.md:4:[vcrpy](https://pypi.org/project/vcrpy/). Furthermore, some of the unit tests use the [pytest-snapshot](https://pypi.org/project/pytest-snapshot/)\npackages/gooddata-sdk/tests/overview.md:39:## Component tests with vcrpy\npackages/gooddata-sdk/tests/overview.md:41:The vcrpy simplifies mocking HTTP endpoints. The component tests use the GoodData microservices environment\npackages/gooddata-sdk/tests/overview.md:48:Additionally, make sure that every time you use vcrpy, you configure the tool:\npackages/gooddata-sdk/tests/overview.md:62:gd_vcr = vcr.VCR(filter_headers=[\"authori", "truncated": true}]} +{"ts": 1778573328.6520123, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_015BANonUUULbobrYPaoaeY3", "input": "{\"pattern\": \"**/conftest.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\"}", "truncated": false}]} +{"ts": 1778573328.6897714, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015BANonUUULbobrYPaoaeY3", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/conftest.py\npackages/gooddata-sdk/tests/conftest.py", "truncated": false}]} +{"ts": 1778573331.1544678, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01UTe6dvrsWjXXkrLGT4rTh7", "input": "{\"pattern\": \"**/vcrpy_utils.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778573331.187915, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UTe6dvrsWjXXkrLGT4rTh7", "is_error": false, "content": "packages/tests-support/src/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/vcrpy_utils.py", "truncated": false}]} +{"ts": 1778573337.2291749, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_019wmgccLAKuJsk6BxrUZ3Td", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\"}", "truncated": false}]} +{"ts": 1778573337.4267926, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_019wmgccLAKuJsk6BxrUZ3Td", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} +{"ts": 1778573403.8686192, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the VCR setup much better! Key insights:\n\n1. **VCR record mode**: `RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE`\n - Without `OVERWRITE` env var: `RecordMode.ONCE` - records if cassette doesn't exist, replays if it does\n - With `OVERWRITE`: re-records everything\n\n2. **Body matching**: The custom body matcher strips env-specific fields (`password`, `token`, `url`, `username`, `privateKey`, etc.) before comparing. This means the PUT body will match even if the datasource URL/username differ.\n\n\n3. **Normalization**: The VCR normalizes org IDs, hostnames, and other environment-specific values so cassettes recorded with one org can match requests from different environments.\n\nSo the body matcher is stripping those sensitive fields like `username` and `password` before comparison, which should allow the cassette's PUT interactions to match the live server's requests. But then why isn't it working?\n\nLet me check the match configuration again\u2014it's set to match on method, path, query, and body. The body matching strips environment-specific fields, so the cassette's PUT to `/api/v1/layout/organization` should match the incoming request. Looking at the cassette's response for that second PUT, I'm seeing an error about invalid auth properties\u2014the datasource has a username but no password, which violates the allowed auth combinations.\n\nThe test is getting the exact same error message back, but the traceId is different. Since `X-GDC-TRACE-ID` is in the non-static headers list that gets stripped during matching, that shouldn't cause a mismatch. The real issue is that the traceId in the actual response doesn't match what's in the cassette, which means either the cassette isn't being used or there's something else filtering the response.\n\nActually, wait\u2014with `RecordMode.ONCE`, VCR should replay from the cassette if it exists, but if a request doesn't match any recorded interaction or if there are more requests than recorded, it might fall back", "truncated": true}]} +{"ts": 1778573403.8687866, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the service more broadly and related tests:", "truncated": false}]} +{"ts": 1778573404.6209807, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01MKnRXfZ6MfaCMR5YDs9jHR", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 620, \"limit\": 130}", "truncated": false}]} +{"ts": 1778573404.6631484, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MKnRXfZ6MfaCMR5YDs9jHR", "is_error": false, "content": "620\t llm_provider_patch.id, llm_provider_patch_document.to_api(), _check_return_type=False\n621\t )\n622\t return CatalogLlmProvider.from_api(response.data)\n623\t\n624\t def delete_llm_provider(self, id: str) -> None:\n625\t \"\"\"Delete an LLM provider.\n626\t\n627\t Args:\n628\t id: LLM provider identifier\n629\t \"\"\"\n630\t self._entities_api.delete_entity_llm_providers(id, _check_return_type=False)\n631\t\n632\t # Layout APIs\n633\t\n634\t def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:\n635\t \"\"\"\n636\t Get all declarative notification channels in the current organization.\n637\t\n638\t Returns:\n639\t list[CatalogDeclarativeNotificationChannel]:\n640\t List of declarative notification channels.\n641\t \"\"\"\n642\t return [\n643\t CatalogDeclarativeNotificationChannel.from_api(nc)\n644\t for nc in self._layout_api.get_notification_channels_layout().notification_channels\n645\t ]\n646\t\n647\t def put_declarative_notification_channels(\n648\t self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n649\t ) -> None:\n650\t \"\"\"\n651\t Put declarative notification channels in the current organization.\n652\t\n653\t Args:\n654\t notification_channels (list[CatalogDeclarativeNotificationChannel]):\n655\t List of declarative notification channels.\n656\t\n657\t Returns:\n658\t None\n659\t \"\"\"\n660\t api_ncs = [nc.to_api() for nc in notification_channels]\n661\t self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n662\t\n663\t def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:\n664\t \"\"\"\n665\t Get all declarative identity providers in the current organization.\n666\t\n667\t Returns:\n668\t list[CatalogDeclarativeIdentit", "truncated": true}]} +{"ts": 1778573430.7477183, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern clearly! For `notification_channels`, `identity_providers`, and `export_templates`, each has a DEDICATED API endpoint:\n- `get_notification_channels_layout()` / `set_notification_channels()`\n- `get_identity_providers_layout()` / `set_identity_providers()`\n- `get_export_templates_layout()` / `set_export_templates()`\n\nThese are all targeted endpoints that DON'T affect other org layout parts.\n\nBut for `ip_allowlist_policies`, there's NO dedicated endpoint! The only way to access them is through the full `get/set_organization_layout`.\n\n\nThe read-modify-write pattern breaks because the GET returns masked passwords in data sources, but the PUT rejects them if there's a username without a password. The real question is whether I can strip out the data sources entirely before sending the PUT\u2014but that only works if the server doesn't delete them when they're missing from the request.\n\nLooking at the endpoint semantics, this is a declarative PUT that likely replaces all entities, which means omitting data sources would probably delete them. That's risky. Alternatively, maybe the server uses PATCH semantics and only updates what's included? The cassette shows a 400 error when the PUT body contains data sources with username but no password, so the server is validating the structure. Even removing just the username field wouldn't help\u2014the server probably requires both username and password together for USERNAME_PASSWORD authentication.\n\nI'm wondering if there's a separate `put_data_sources_layout` endpoint that handles data sources independently, which would let me avoid sending them in the organization layout PUT altogether. I need to decide on the fix: remove `data_sources` from the org layout before PUTting it, swap the test user to `demo2` and the group to `demoGroup` (both of which exist in the cassette), and delete the stale cassette so it gets re-recorded. But I'm wondering if removing the data sources will actually work, or if there's something else", "truncated": true}]} +{"ts": 1778573430.7515438, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the `set_organization_layout` endpoint definition in the generated client to understand the expected request body:", "truncated": false}]} +{"ts": 1778573431.8523152, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01K7wUW1PvC1gwGxwavqxVK4", "input": "{\"pattern\": \"set_organization_layout_endpoint|organizationLayout|data_source\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50, \"offset\": 5870}", "truncated": false}]} +{"ts": 1778573432.1605437, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01K7wUW1PvC1gwGxwavqxVK4", "is_error": false, "content": "No matches found\n\n[Showing results with pagination = offset: 5870]", "truncated": false}]} +{"ts": 1778573432.161245, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_014V9m7nGcE977Hqc4KiRgmU", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\"}", "truncated": false}]} +{"ts": 1778573432.1945355, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014V9m7nGcE977Hqc4KiRgmU", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_cl", "truncated": false}]} +{"ts": 1778573434.3087003, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NrBbt2jXFaNogoBKWnQXB3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 6450, \"limit\": 80}", "truncated": false}]} +{"ts": 1778573434.3424428, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NrBbt2jXFaNogoBKWnQXB3", "is_error": false, "content": "6450\t )\n6451\t kwargs['_check_return_type'] = kwargs.get(\n6452\t '_check_return_type', True\n6453\t )\n6454\t kwargs['_spec_property_naming'] = kwargs.get(\n6455\t '_spec_property_naming', False\n6456\t )\n6457\t kwargs['_content_type'] = kwargs.get(\n6458\t '_content_type')\n6459\t kwargs['_host_index'] = kwargs.get('_host_index')\n6460\t kwargs['_request_auths'] = kwargs.get('_request_auths', None)\n6461\t kwargs['workspace_id'] = \\\n6462\t workspace_id\n6463\t kwargs['declarative_workspace_permissions'] = \\\n6464\t declarative_workspace_permissions\n6465\t return self.set_workspace_permissions_endpoint.call_with_http_info(**kwargs)\n6466\t\n6467\t def set_workspaces_layout(\n6468\t self,\n6469\t declarative_workspaces,\n6470\t **kwargs\n6471\t ):\n6472\t \"\"\"Set all workspaces layout # noqa: E501\n6473\t\n6474\t Sets complete layout of workspaces, their hierarchy, models. # noqa: E501\n6475\t This method makes a synchronous HTTP request by default. To make an\n6476\t asynchronous HTTP request, please pass async_req=True\n6477\t\n6478\t >>> thread = api.set_workspaces_layout(declarative_workspaces, async_req=True)\n6479\t >>> result = thread.get()\n6480\t\n6481\t Args:\n6482\t declarative_workspaces (DeclarativeWorkspaces):\n6483\t\n6484\t Keyword Args:\n6485\t _return_http_data_only (bool): response data without head status\n6486\t code and headers. Default is True.\n6487\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n6488\t will be returned without reading/decoding response data.\n6489\t Default is True.\n6490\t _request_timeout (int/float/tuple): timeout setting for this request. If\n6491\t one number provided, it will be total request timeout. It can also\n6492\t be a pair (tuple) of (conn", "truncated": true}]} +{"ts": 1778573438.0769076, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I need to understand what happens when `data_sources` is omitted from the `set_organization_layout` PUT. Let me look at how the ModelNormal object is serialized in the API client. When we call `set_organization_layout(org_layout)`, it serializes the org_layout object to JSON. If we delete `data_sources` from the org_layout object, it won't be included in the JSON.\n\nActually, let me look at the GoodData documentation or schemas to understand if `set_organization_layout` accepts data sources.\n\nLet me look at the OpenAPI schema:", "truncated": false}]} +{"ts": 1778573438.6275938, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LFJRJYe4tNaED3AE8agWbL", "input": "{\"pattern\": \"**/openapi*.json\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} +{"ts": 1778573438.647309, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LFJRJYe4tNaED3AE8agWbL", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778573439.0766628, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01W4e4HNYD1WjbpZWHuZYaMo", "input": "{\"pattern\": \"**/*.yaml\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} +{"ts": 1778573439.1250844, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01W4e4HNYD1WjbpZWHuZYaMo", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778573440.8725183, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01RuphSpJKEP3WM9topeCAgh", "input": "{\"pattern\": \"**/*.json\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} +{"ts": 1778573440.9493003, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01RuphSpJKEP3WM9topeCAgh", "is_error": false, "content": "schemas/gooddata-afm-client.json\nschemas/gooddata-api-client.json\nschemas/gooddata-automation-client.json\nschemas/gooddata-export-client.json\nschemas/gooddata-metadata-client.json\nschemas/gooddata-result-client.json\nschemas/gooddata-scan-client.json", "truncated": false}]} +{"ts": 1778573445.4138584, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Agent", "id": "toolu_01HVGT66PbvTDfV2X1iXzZBN", "input": "{\"description\": \"Find set_organization_layout request schema\", \"subagent_type\": \"Explore\", \"prompt\": \"In the file /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json, find the definition of the `set_organization_layout` operation (likely under /api/v1/layout/organization PUT). Look for:\\n1. The request body schema - what fields does it accept?\\n2. Is `dataSources` a required field or optional?\\n3. What happens if dataSources is omitted?\\n\\nAlso search for any documentation string like \\\"Sets complete layout\\\" to find the relevant endpoint.\\n\\nQuick search - just look at the PUT /layout/organization operation definition. Report back what fields are in the request body schema (DeclarativeOrganization) and whether data_sources is required.\"}", "truncated": false}]} +{"ts": 1778573445.457617, "type": "system"} +{"ts": 1778573445.4577394, "type": "user", "blocks": [{"type": "text", "text": "In the file /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json, find the definition of the `set_organization_layout` operation (likely under /api/v1/layout/organization PUT). Look for:\n1. The request body schema - what fields does it accept?\n2. Is `dataSources` a required field or optional?\n3. What happens if dataSources is omitted?\n\nAlso search for any documentation string like \"Sets complete layout\" to find the relevant endpoint.\n\nQuick search - just look at the PUT /layout/organization operation definition. Report back what fields are in the request body schema (DeclarativeOrganization) and whether data_sources is required.", "truncated": false}]} +{"ts": 1778573447.096374, "type": "system"} +{"ts": 1778573447.0965405, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Tzv5YYVqFVuV4H4ZXb7AAk", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"limit\": 100}", "truncated": false}]} +{"ts": 1778573447.2999392, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Tzv5YYVqFVuV4H4ZXb7AAk", "is_error": false, "content": "1\t{\n2\t \"components\": {\n3\t \"parameters\": {\n4\t \"idPathParameter\": {\n5\t \"in\": \"path\",\n6\t \"name\": \"id\",\n7\t \"required\": true,\n8\t \"schema\": {\n9\t \"pattern\": \"^(?!\\\\.)[.A-Za-z0-9_-]{1,255}$\",\n10\t \"type\": \"string\"\n11\t }\n12\t },\n13\t \"page\": {\n14\t \"description\": \"Zero-based page index (0..N)\",\n15\t \"in\": \"query\",\n16\t \"name\": \"page\",\n17\t \"schema\": {\n18\t \"default\": 0,\n19\t \"type\": \"integer\"\n20\t }\n21\t },\n22\t \"size\": {\n23\t \"description\": \"The size of the page to be returned\",\n24\t \"in\": \"query\",\n25\t \"name\": \"size\",\n26\t \"schema\": {\n27\t \"default\": 20,\n28\t \"type\": \"integer\"\n29\t }\n30\t },\n31\t \"sort\": {\n32\t \"description\": \"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.\",\n33\t \"in\": \"query\",\n34\t \"name\": \"sort\",\n35\t \"schema\": {\n36\t \"items\": {\n37\t \"type\": \"string\"\n38\t },\n39\t \"type\": \"array\"\n40\t }\n41\t }\n42\t },\n43\t \"responses\": {\n44\t \"Deleted\": {\n45\t \"description\": \"Successfully deleted\"\n46\t }\n47\t },\n48\t \"schemas\": {\n49\t \"AFM\": {\n50\t \"description\": \"Top level executable entity. Combination of [A]ttributes, [F]ilters & [M]etrics.\",\n51\t \"properties\": {\n52\t \"attributes\": {\n53\t \"description\": \"Attributes to be used in the computation.\",\n54\t \"items\": {\n55\t \"$ref\": \"#/components/schemas/AttributeItem\"\n56\t },\n57\t \"type\": \"array\"\n58\t },\n59\t \"auxMeasures\": {\n60\t \"description\": \"Metrics to be referenced from other AFM objects (e.g. filters) but not included in the result.\",\n61\t \"items\": {\n62\t \"$ref\": \"#/components/schemas/MeasureItem\"\n63\t },\n64\t \"type\": \"array\"\n65\t ", "truncated": true}]} +{"ts": 1778573447.3045278, "type": "system"} +{"ts": 1778573447.3046682, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_0158euZCKUW1wvNFFWSAcvwn", "input": "{\"command\": \"grep -n \\\"set_organization_layout\\\\|/api/v1/layout/organization\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json | head -20\"}", "truncated": false}]} +{"ts": 1778573447.340812, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0158euZCKUW1wvNFFWSAcvwn", "is_error": true, "content": "Blocked: grep -n \"set_organization_layout\\|/api/v1/layout/organization\" /home/runner/_wor", "truncated": false}]} +{"ts": 1778573450.0718591, "type": "system"} +{"ts": 1778573450.072006, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_015zNBEYdVdUc886BeSKKc4s", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\"}", "truncated": false}]} +{"ts": 1778573450.1048636, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015zNBEYdVdUc886BeSKKc4s", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json", "truncated": false}]} +{"ts": 1778573451.6276126, "type": "system"} +{"ts": 1778573451.6277678, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01A4GjxJyyy7G3t2cBdxD5cN", "input": "{\"pattern\": \"layout/organization|set_organization_layout|Sets complete layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778573451.6587243, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01A4GjxJyyy7G3t2cBdxD5cN", "is_error": false, "content": "64785: \"/api/v1/layout/organization\": {\n64831: \"description\": \"Sets complete layout of organization, like workspaces, user-groups, etc.\",\n64861: \"/api/v1/layout/organization/permissions\": {\n65367: \"description\": \"Sets complete layout of workspaces, their hierarchy, models.\",", "truncated": false}]} +{"ts": 1778573453.0330114, "type": "system"} +{"ts": 1778573453.0331602, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01WfnptckTScd2rkNeWmAbww", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"offset\": 64785, \"limit\": 100}", "truncated": false}]} +{"ts": 1778573453.065535, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WfnptckTScd2rkNeWmAbww", "is_error": false, "content": "64785\t \"/api/v1/layout/organization\": {\n64786\t \"get\": {\n64787\t \"description\": \"Retrieve complete layout of organization, workspaces, user-groups, etc.\",\n64788\t \"operationId\": \"getOrganizationLayout\",\n64789\t \"parameters\": [\n64790\t {\n64791\t \"in\": \"query\",\n64792\t \"name\": \"exclude\",\n64793\t \"required\": false,\n64794\t \"schema\": {\n64795\t \"items\": {\n64796\t \"description\": \"Defines properties which should not be included in the payload.\",\n64797\t \"enum\": [\n64798\t \"ACTIVITY_INFO\"\n64799\t ],\n64800\t \"type\": \"string\"\n64801\t },\n64802\t \"type\": \"array\"\n64803\t }\n64804\t }\n64805\t ],\n64806\t \"responses\": {\n64807\t \"200\": {\n64808\t \"content\": {\n64809\t \"application/json\": {\n64810\t \"schema\": {\n64811\t \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64812\t }\n64813\t }\n64814\t },\n64815\t \"description\": \"Retrieved all parts of an organization.\"\n64816\t }\n64817\t },\n64818\t \"summary\": \"Get organization layout\",\n64819\t \"tags\": [\n64820\t \"layout\",\n64821\t \"Organization - Declarative APIs\"\n64822\t ],\n64823\t \"x-gdc-security-info\": {\n64824\t \"description\": \"Permission required to get organization layout.\",\n64825\t \"permissions\": [\n64826\t \"MANAGE\"\n64827\t ]\n64828\t }\n64829\t },\n64830\t \"put\": {\n64831\t \"description\": \"Sets complete layout of organization, like workspaces, user-groups, etc.\",\n64832\t \"operationId\": \"setOrganizationLayout\",\n64833\t \"requestBody\": {\n64834\t \"content\": {\n64835\t \"application/json\": {\n64836\t \"schema\": {\n64837\t \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n648", "truncated": true}]} +{"ts": 1778573455.2271101, "type": "system"} +{"ts": 1778573455.2272766, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_018HUB8ZRTKV7NJZvRGYHEvN", "input": "{\"pattern\": \"\\\"DeclarativeOrganization\\\":\\\\s*\\\\{\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} +{"ts": 1778573455.2667735, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018HUB8ZRTKV7NJZvRGYHEvN", "is_error": false, "content": "Found 1 file\nschemas/gooddata-api-client.json", "truncated": false}]} +{"ts": 1778573456.8281085, "type": "system"} +{"ts": 1778573456.828594, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_018NnAAPHNdjEWs79CLP8ayJ", "input": "{\"pattern\": \"DeclarativeOrganization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} +{"ts": 1778573456.8667054, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018NnAAPHNdjEWs79CLP8ayJ", "is_error": false, "content": "7301: \"DeclarativeOrganization\": {\n7353: \"$ref\": \"#/components/schemas/DeclarativeOrganizationInfo\"\n7385: \"DeclarativeOrganizationInfo\": {\n7446: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"\n7473: \"DeclarativeOrganizationPermission\": {\n64811: \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64837: \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64871: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"\n64901: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"", "truncated": false}]} +{"ts": 1778573458.093222, "type": "system"} +{"ts": 1778573458.093363, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01FZzt6yj36H9DK5a2kFwPMg", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"offset\": 7301, \"limit\": 100}", "truncated": false}]} +{"ts": 1778573458.123855, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01FZzt6yj36H9DK5a2kFwPMg", "is_error": false, "content": "7301\t \"DeclarativeOrganization\": {\n7302\t \"description\": \"Complete definition of an organization in a declarative form.\",\n7303\t \"properties\": {\n7304\t \"agents\": {\n7305\t \"items\": {\n7306\t \"$ref\": \"#/components/schemas/DeclarativeAgent\"\n7307\t },\n7308\t \"type\": \"array\"\n7309\t },\n7310\t \"customGeoCollections\": {\n7311\t \"items\": {\n7312\t \"$ref\": \"#/components/schemas/DeclarativeCustomGeoCollection\"\n7313\t },\n7314\t \"type\": \"array\"\n7315\t },\n7316\t \"dataSources\": {\n7317\t \"items\": {\n7318\t \"$ref\": \"#/components/schemas/DeclarativeDataSource\"\n7319\t },\n7320\t \"type\": \"array\"\n7321\t },\n7322\t \"exportTemplates\": {\n7323\t \"items\": {\n7324\t \"$ref\": \"#/components/schemas/DeclarativeExportTemplate\"\n7325\t },\n7326\t \"type\": \"array\"\n7327\t },\n7328\t \"identityProviders\": {\n7329\t \"items\": {\n7330\t \"$ref\": \"#/components/schemas/DeclarativeIdentityProvider\"\n7331\t },\n7332\t \"type\": \"array\"\n7333\t },\n7334\t \"ipAllowlistPolicies\": {\n7335\t \"items\": {\n7336\t \"$ref\": \"#/components/schemas/DeclarativeIpAllowlistPolicy\"\n7337\t },\n7338\t \"type\": \"array\"\n7339\t },\n7340\t \"jwks\": {\n7341\t \"items\": {\n7342\t \"$ref\": \"#/components/schemas/DeclarativeJwk\"\n7343\t },\n7344\t \"type\": \"array\"\n7345\t },\n7346\t \"notificationChannels\": {\n7347\t \"items\": {\n7348\t \"$ref\": \"#/components/schemas/DeclarativeNotificationChannel\"\n7349\t },\n7350\t \"type\": \"array\"\n7351\t },\n7352\t \"organization\": {\n7353\t \"$ref\": \"#/components/schemas/DeclarativeOrganizationInfo\"\n7354\t },\n7355\t \"userGroups\": {\n7356\t ", "truncated": true}]} +{"ts": 1778573462.5523498, "type": "system"} +{"ts": 1778573462.552546, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HVGT66PbvTDfV2X1iXzZBN", "is_error": false, "content": "[{\"type\": \"text\", \"text\": \"Perfect! I have all the information needed. Let me provide you with the findings:\\n\\n## Summary\\n\\n**Operation:** PUT `/api/v1/layout/organization` (operationId: `setOrganizationLayout`)\\n\\n**Request Body Schema:** The PUT endpoint accepts a `DeclarativeOrganization` object.\\n\\n**Fields in DeclarativeOrganization:**\\n1. `agents` (optional) - array\\n2. `customGeoCollections` (optional) - array\\n3. `dataSources` (optional) - array of DeclarativeDataSource objects\\n4. `exportTemplates` (optional) - array\\n5. `identityProviders` (optional) - array\\n6. `ipAllowlistPolicies` (optional) - array\\n7. `jwks` (optional) - array\\n8. `notificationChannels` (optional) - array\\n9. `organization` (required) - DeclarativeOrganizationInfo object\\n10. `userGroups` (optional) - array\\n11. `users` (optional) - array\\n12. `workspaceDataFilters` (optional) - array\\n13. `workspaces` (optional) - array\\n\\n**Is `dataSources` Required?** **NO** - it is optional. The only required field in `DeclarativeOrganization` is `organization` (line 7380-7381 shows `\\\"required\\\": [\\\"organization\\\"]`).\\n\\n**What happens if dataSources is omitted?** If `dataSources` is omitted, the request will still be valid as long as the `organization` field is provided. The endpoint will process the organization layout without updating/setting any data sources.\\n\\n**File location:** `/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json`\\n- PUT operation definition: lines 64830-64859\\n- DeclarativeOrganization schema: lines 7301-7383\"}]", "truncated": false}]} +{"ts": 1778573513.3000798, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "`dataSources` is optional in the `set_organization_layout` request. The question is still: if `dataSources` is omitted, does the server:\n1. Delete all existing data sources (treats omission as \"empty list\"), or\n2. Keep existing data sources unchanged (treats omission as \"no change\")\n\nThe schema says it's optional, but that only tells us the request is valid without it. The server behavior (whether it deletes or preserves existing datasources) depends on the API implementation.\n\nLooking at the description: \"Sets complete layout of organization\". If it sets the COMPLETE layout, omitting data sources might delete them.\n\n\nHowever, there's a dedicated `put_data_sources_layout` endpoint, which suggests data sources have their own lifecycle and aren't managed through `set_organization_layout`. The VCR utilities strip environment-specific fields like passwords and URLs from request bodies for matching, but these are still included in actual requests. The real issue is that the test fails when including the datasource with incomplete auth, returning a 400 error\u2014so removing it from the PUT request might be the fix.\n\nLet me check if other tests use `set_organization_layout` to see if omitting datasources is safe, and I should also look at the conftest to understand how the session snapshot mechanism works. The warning about restoring snapshots suggests the test environment can recover from accidental deletions anyway.\n\nI'll take a pragmatic approach: remove `data_sources` from the org_layout object before the PUT request using a safe check, and update the test to use valid credentials like `demo2` and `demoGroup` instead of the invalid ones.\n\nLooking at the cassette data, I can see which users and groups actually exist in the test environment, but the real issue is that the cassette was recorded against the `default` org while the live server uses `python-sdk-dex`, and they likely have different user sets. The error confirms `employee123` doesn't exist in `python-sdk-dex`, so ", "truncated": true}]} +{"ts": 1778573513.3002434, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at other organization layout tests to understand patterns:", "truncated": false}]} +{"ts": 1778573513.8653922, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01NpjExXaqjXfVaD8f6gjgfg", "input": "{\"pattern\": \"layout_organization|organization_layout|set_organization|declarative_organization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} +{"ts": 1778573514.2154393, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NpjExXaqjXfVaD8f6gjgfg", "is_error": false, "content": "packages/gooddata-sdk/tests/conftest.py:263: snapshot[\"org_permissions\"] = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/conftest.py:330: sdk.catalog_permission.put_declarative_organization_permissions(snapshot[\"org_permissions\"])\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:71: sdk.catalog_permission.put_declarative_organization_permissions([default_catalog_organization_permission])\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:73: catalog_permissions = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:198:@gd_vcr.use_cassette(str(_fixtures_dir / \"put_declarative_organization_permissions.yaml\"))\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:199:def test_put_and_get_declarative_organization_permissions(test_config, snapshot_org_permissions):\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:200: expected_json_path = _current_dir / \"expected\" / \"declarative_organization_permissions.json\"\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:206: declarative_organization_permissions = [\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:211: sdk.catalog_permission.put_declarative_organization_permissions(declarative_organization_permissions)\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:213: catalog_declarative_permissions_after_put = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:239: catalog_declarative_permissions_initial = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/conftest.py:191: original = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/conftest.py:198: sdk.catalog_permission.put_", "truncated": true}]} +{"ts": 1778573514.4718747, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NnPhHMKEN9Hx4TgsLbtJvX", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 280, \"limit\": 30}", "truncated": false}]} +{"ts": 1778573514.5075514, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NnPhHMKEN9Hx4TgsLbtJvX", "is_error": false, "content": "280\t except Exception as e:\n281\t logger.error(f\"Snapshot capture failed [workspace list for permissions]: {e}\")\n282\t snapshot[\"ws_permissions\"] = ws_permissions\n283\t\n284\t logger.info(\"Session snapshot captured\")\n285\t\n286\t # --- Tests run ---\n287\t yield snapshot\n288\t\n289\t # --- Restore (only if failures) ---\n290\t if not _session_has_failures:\n291\t logger.info(\"All tests passed \u2014 skipping session restore\")\n292\t return\n293\t\n294\t logger.warning(\"Test failures detected \u2014 restoring session snapshot...\")\n295\t\n296\t # Restore order matters: users/groups \u2192 data sources \u2192 workspaces \u2192\n297\t # workspace data filters \u2192 org permissions \u2192 notification channels \u2192\n298\t # per-workspace permissions\n299\t\n300\t if \"users_groups\" in snapshot:\n301\t try:\n302\t sdk.catalog_user.put_declarative_users_user_groups(snapshot[\"users_groups\"])\n303\t logger.info(\"Restored [users_groups]\")\n304\t except Exception as e:\n305\t logger.error(f\"RESTORE FAILED [users_groups]: {e}\")\n306\t\n307\t if \"data_sources\" in snapshot:\n308\t try:\n309\t sdk.catalog_data_source.put_declarative_data_sources(snapshot[\"data_sources\"], _credentials_path)", "truncated": false}]} +{"ts": 1778573517.0844796, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GQgnaxgpq2exB292aVd9b3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 200, \"limit\": 80}", "truncated": false}]} +{"ts": 1778573517.1163845, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GQgnaxgpq2exB292aVd9b3", "is_error": false, "content": "200\t Layout files are stored under gooddata_layouts/default/. On staging, the SDK\n201\t resolves org_id to the real staging value. Symlinks make both paths point to\n202\t the same directory.\n203\t \"\"\"\n204\t org_id = test_config.get(\"org_id\", \"default\")\n205\t symlinks_created = []\n206\t if org_id != \"default\":\n207\t for layout_root in _LAYOUT_ROOTS:\n208\t symlink = layout_root / org_id\n209\t if not symlink.exists():\n210\t symlink.symlink_to(\"default\")\n211\t symlinks_created.append(symlink)\n212\t logger.info(f\"Created org_id symlinks for '{org_id}'\")\n213\t\n214\t yield\n215\t\n216\t for symlink in symlinks_created:\n217\t symlink.unlink(missing_ok=True)\n218\t\n219\t\n220\t# ---------------------------------------------------------------------------\n221\t# Session-level snapshot/restore \u2014 safety net for staging\n222\t# ---------------------------------------------------------------------------\n223\t\n224\t\n225\t@pytest.fixture(scope=\"session\", autouse=True)\n226\tdef staging_session_snapshot(test_config, staging_preflight):\n227\t \"\"\"When staging: true, capture full environment state before tests run.\n228\t\n229\t On teardown, if any test failed, restore everything to the captured state.\n230\t This is the last line of defense \u2014 per-test snapshot fixtures are the first.\n231\t \"\"\"\n232\t if not test_config.get(\"staging\", False):\n233\t yield\n234\t return\n235\t\n236\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n237\t\n238\t # --- Capture ---\n239\t snapshot = {}\n240\t logger.info(\"Capturing session snapshot...\")\n241\t\n242\t try:\n243\t snapshot[\"users_groups\"] = sdk.catalog_user.get_declarative_users_user_groups()\n244\t except Exception as e:\n245\t logger.error(f\"Snapshot capture failed [users_groups]: {e}\")\n246\t\n247\t try:\n248\t snapshot[\"data_sources\"] = sdk.catalog_data_source.get_declarative_data_sources()\n249\t except Excep", "truncated": true}]} +{"ts": 1778573548.3740118, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see! The conftest snapshot captures:\n1. `users_groups`\n2. `data_sources` (via `get_declarative_data_sources`) \n3. `workspaces`\n4. `workspace_data_filters`\n5. `org_permissions`\n6. `notification_channels`\n7. Per-workspace permissions\n\nNotice that `ip_allowlist_policies` is NOT in the snapshot. The conftest doesn't snapshot/restore IP allowlist policies. This means if our test accidentally modifies them and fails to restore, they won't be restored by the session snapshot.\n\n\nThe conftest also uses a separate API for data sources\u2014`get_declarative_data_sources` and `put_declarative_data_sources`\u2014rather than managing them through `set_organization_layout`. This separation strongly suggests that `set_organization_layout` doesn't control data sources, so omitting them from a PUT request wouldn't delete existing ones.\n\nMy approach is to remove `data_sources` from the org layout object before PUTting it in `put_declarative_ip_allowlist_policies`, update the test values to use `demo2` and `demoGroup`, and delete the stale cassette so it gets re-recorded. Now I need to figure out how to strip `data_sources` from a ModelNormal instance and understand what type `get_organization_layout` returns when type checking is disabled.\n\nWith `_check_return_type=False`, I get a ModelNormal instance where attributes are accessed and modified through regular attribute assignment. The real question is whether setting `data_sources` to an empty list would work, but the server's validation error suggests it actually processes the `data_sources` field in the PUT request rather than ignoring it. This means I can't just pass an empty list\u2014I need to actually remove the field entirely from the request body. The server is rejecting the PUT because the datasource auth is incomplete, which means it's actively validating data sources rather than ignoring them. The `_ENV_SPECIFIC_BODY_FIELDS` mechanism strips environment-specific credentials from VCR matching, so the intended pattern is to include d", "truncated": true}]} +{"ts": 1778573548.3741748, "type": "assistant", "blocks": [{"type": "text", "text": "Let me understand how ModelNormal handles attribute deletion and look at existing tests that do similar read-modify-write operations:", "truncated": false}]} +{"ts": 1778573549.4657626, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DjBDHHyW3vZeum8jugFPDA", "input": "{\"pattern\": \"_data_store|__delattr__|__setattr__\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model_utils.py\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} +{"ts": 1778573549.9656549, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DjBDHHyW3vZeum8jugFPDA", "is_error": false, "content": "176: self.__dict__['_data_store'][name] = value\n186: def __setattr__(self, attr, value):\n465: return self.__dict__['_data_store'].get(name, default)\n483: return name in self.__dict__['_data_store']\n494: this_val = self._data_store['value']\n495: that_val = other._data_store['value']\n520: return self.__dict__['_data_store'].get(name, default)\n538: return name in self.__dict__['_data_store']\n558: if not set(self._data_store.keys()) == set(other._data_store.keys()):\n560: for _var_name, this_val in self._data_store.items():\n561: that_val = other._data_store[_var_name]\n589: they are returned from the self._data_store or the data stores in the instances\n658: if name in model_instance._data_store:\n659: v = model_instance._data_store[name]\n697: if name in model_instance._data_store:\n720: if not set(self._data_store.keys()) == set(other._data_store.keys()):\n722: for _var_name, this_val in self._data_store.items():\n723: that_val = other._data_store[_var_name]\n1684: extract_item = lambda item: (item[0], model_to_dict(item[1], serialize=serialize)) if hasattr(item[1], '_data_store') else item\n1693: for attr, value in model_instance._data_store.items():\n1729: elif hasattr(value, '_data_store'):", "truncated": false}]} +{"ts": 1778573549.9972496, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01QeHe69ScxvYp59VFxs4j7a", "input": "{\"pattern\": \"**/catalog_data_source_service.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src\"}", "truncated": false}]} +{"ts": 1778573550.0580559, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QeHe69ScxvYp59VFxs4j7a", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778573552.4546952, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GhjRjvSZcjPj3UnC61u3AG", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model_utils.py\", \"offset\": 170, \"limit\": 40}", "truncated": false}]} From 4aa0d56a995446c9d1b719aa1cd7de7fbda60912 Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Wed, 13 May 2026 07:34:10 +0000 Subject: [PATCH 4/6] fix(gooddata-sdk): address review feedback --- .../layout_ip_allowlist_policies.yaml | 21483 ---------------- .../catalog/test_catalog_organization.py | 8 +- transcripts/fix-C009-attempt1.jsonl | 127 - transcripts/fix-C009-attempt2.jsonl | 144 - 4 files changed, 4 insertions(+), 21758 deletions(-) delete mode 100644 packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml delete mode 100644 transcripts/fix-C009-attempt1.jsonl delete mode 100644 transcripts/fix-C009-attempt2.jsonl diff --git a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml deleted file mode 100644 index 70642f078..000000000 --- a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml +++ /dev/null @@ -1,21483 +0,0 @@ -interactions: - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: &id001 - - PLACEHOLDER - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: - - allowedSources: - - 203.0.113.10/32 - - 198.51.100.0/24 - id: admin-vpn-only - userGroups: - - id: group.admins - type: userGroup - users: - - id: employee123 - type: user - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows revenue - per $ spend, for each campaign, to demonstrate, how - campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Accept-Encoding: - - br, gzip, deflate - Content-Type: - - application/json - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: PUT - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - detail: 'Some of given referenced ''users'' entities do not exist. Not existing - IDs: [Identifier(employee123)/Organization(default)]' - status: 400 - title: Bad Request - traceId: NORMALIZED_TRACE_ID_000000000000 - headers: - Content-Type: - - application/problem+json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 400 - message: Bad Request - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows revenue - per $ spend, for each campaign, to demonstrate, how - campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Accept-Encoding: - - br, gzip, deflate - Content-Type: - - application/json - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: PUT - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - detail: 'Invalid combination of auth properties. Only none, user + password, - token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, - user: , password: , token: , key-pair: , clientId: , - clientSecret: ' - status: 400 - title: Bad Request - traceId: NORMALIZED_TRACE_ID_000000000000 - headers: - Content-Type: - - application/problem+json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 400 - message: Bad Request - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: - - allowedSources: - - 203.0.113.10/32 - - 198.51.100.0/24 - id: admin-vpn-only - userGroups: - - id: group.admins - type: userGroup - users: - - id: employee123 - type: user - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows revenue - per $ spend, for each campaign, to demonstrate, how - campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Accept-Encoding: - - br, gzip, deflate - Content-Type: - - application/json - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: PUT - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - detail: 'Some of given referenced ''users'' entities do not exist. Not existing - IDs: [Identifier(employee123)/Organization(default)]' - status: 400 - title: Bad Request - traceId: NORMALIZED_TRACE_ID_000000000000 - headers: - Content-Type: - - application/problem+json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 400 - message: Bad Request - - request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - br, gzip, deflate - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: GET - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows - revenue per $ spend, for each campaign, to demonstrate, - how campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and - Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Content-Type: - - application/json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 200 - message: OK - - request: - body: - agents: - - aiKnowledge: true - availableToAll: true - enabled: true - id: default-ai-assistant - name: Default GoodData AI Assistant - skillsMode: all - customGeoCollections: [] - dataSources: - - alternativeDataSourceId: ds-put-abc-id - authenticationType: USERNAME_PASSWORD - id: demo-test-ds - name: demo-test-ds - permissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: USE - schema: demo - type: POSTGRESQL - url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer - username: postgres - exportTemplates: [] - identityProviders: - - id: defaultIdp - idpType: DEX_IDP - ipAllowlistPolicies: [] - jwks: [] - notificationChannels: [] - organization: - allowedOrigins: [] - colorPalettes: [] - cspDirectives: [] - earlyAccess: enableAlerting - earlyAccessValues: - - enableAlerting - - enableSmtp - - enablePreAggregationDatasets - - enableScheduling - - enableCompositeGrain - - enableUserManagement - - enableRawExports - - enableFlexibleDashboardLayout - hostname: localhost - id: default - identityProvider: - id: defaultIdp - type: identityProvider - name: Default Organization - permissions: - - assignee: - id: adminGroup - type: userGroup - name: MANAGE - settings: [] - themes: [] - userGroups: - - id: adminGroup - permissions: [] - - id: adminQA1Group - parents: - - id: adminGroup - type: userGroup - permissions: [] - - id: demoGroup - name: demo group - permissions: [] - - id: visitorsGroup - name: visitors - parents: - - id: demoGroup - type: userGroup - permissions: [] - users: - - id: admin - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - email: demo@example.com - firstname: Demo - id: demo - lastname: User - permissions: [] - settings: [] - userGroups: - - id: adminGroup - type: userGroup - - authId: NORMALIZED_AUTH_ID - id: demo2 - permissions: [] - settings: [] - userGroups: - - id: demoGroup - type: userGroup - workspaceDataFilters: - - columnName: wdf__region - id: wdf__region - title: Customer region - workspace: - id: demo - type: workspace - workspaceDataFilterSettings: - - filterValues: - - West - id: region_west - title: Region West - workspace: - id: demo_west - type: workspace - - columnName: wdf__state - id: wdf__state - title: Customer state - workspace: - id: demo_west - type: workspace - workspaceDataFilterSettings: - - filterValues: - - California - id: region_west_california - title: Region West California - workspace: - id: demo_west_california - type: workspace - workspaces: - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: - - assignee: - id: demo2 - type: user - name: MANAGE - - assignee: - id: demoGroup - type: userGroup - name: ANALYZE - id: demo - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - header: - description: The first insight shows a breakdown of - spend by category and campaign. The second shows revenue - per $ spend, for each campaign, to demonstrate, how - campaigns are successful. - title: Spend breakdown and Revenue - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: campaign_spend - type: visualizationObject - properties: {} - title: Campaign Spend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_per_usd_vs_spend_by_campaign - type: visualizationObject - properties: {} - title: Revenue per $ vs Spend by Campaign - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - title: Campaign - - content: - filterContextRef: - identifier: - id: campaign_name_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: DHO simple - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - plugins: - - plugin: - identifier: - id: dashboard_plugin_1 - type: dashboardPlugin - version: '2' - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: dashboard_plugin - title: Dashboard plugin - - content: - filterContextRef: - identifier: - id: region_filter - type: filterContext - layout: - sections: - - items: - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: top_10_products - type: visualizationObject - properties: {} - title: Top 10 Products - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: revenue_trend - type: visualizationObject - properties: {} - title: Revenue Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: customers_trend - type: visualizationObject - properties: {} - title: Customers Trend - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_categories_pie_chart - type: visualizationObject - properties: {} - title: Product Categories Pie Chart - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_breakdown - type: visualizationObject - properties: {} - title: Product Breakdown - type: insight - - size: - xl: - gridWidth: 6 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: product_saleability - type: visualizationObject - properties: {} - title: Product Saleability - type: insight - - size: - xl: - gridWidth: 12 - type: IDashboardLayoutItem - widget: - dateDataSet: - identifier: - id: date - type: dataset - description: '' - drills: [] - ignoreDashboardFilters: [] - insight: - identifier: - id: percent_revenue_per_product_by_customer_and_category - type: visualizationObject - properties: {} - title: '% Revenue per Product by Customer and Category' - type: insight - type: IDashboardLayoutSection - type: IDashboardLayout - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: product_and_category - title: Product & Category - attributeHierarchies: [] - dashboardPlugins: - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_1 - id: dashboard_plugin_1 - title: dashboard_plugin_1 - - content: - url: https://www.example.com - version: '2' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: Testing record dashboard_plugin_2 - id: dashboard_plugin_2 - title: dashboard_plugin_2 - exportDefinitions: [] - filterContexts: - - content: - filters: - - dateFilter: - from: '0' - granularity: GDC.time.month - to: '0' - type: relative - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: campaign_name - type: label - filterElementsBy: [] - localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d - negativeSelection: true - version: '2' - description: '' - id: campaign_name_filter - title: filterContext - - content: - filters: - - attributeFilter: - attributeElements: - uris: [] - displayForm: - identifier: - id: region - type: label - filterElementsBy: [] - localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af - negativeSelection: true - version: '2' - description: '' - id: region_filter - title: filterContext - memoryItems: [] - metrics: - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_active_customers - title: '# of Active Customers' - - content: - format: '#,##0' - maql: SELECT COUNT({attribute/order_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_orders - title: '# of Orders' - - content: - format: '#,##0' - maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT - {metric/revenue} BY {attribute/customer_id}) > 10000 ' - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: amount_of_top_customers - title: '# of Top Customers' - - content: - format: '#,##0.00' - maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: amount_of_valid_orders - title: '# of Valid Orders' - - content: - format: $#,##0 - maql: SELECT SUM({fact/spend}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - format: $#,##0 - maql: SELECT SUM({fact/price}*{fact/quantity}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: order_amount - title: Order Amount - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / {metric/total_revenue} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue - title: '% Revenue' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_customers - title: '% Revenue from Top 10 Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_customers - title: '% Revenue from Top 10% Customers' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_percent_products - title: '% Revenue from Top 10% Products' - - content: - format: '#,##0.0%' - maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ - \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_from_top_10_products - title: '% Revenue from Top 10 Products' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - {attribute/products.category}, ALL OTHER) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_in_category - title: '% Revenue in Category' - - content: - format: '#,##0.0%' - maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY - ALL {attribute/product_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product - title: '% Revenue per Product' - - content: - format: $#,##0 - maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} - IN ("Returned", "Canceled")) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - description: '' - id: revenue - title: Revenue - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Clothing") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-clothing - title: Revenue (Clothing) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ( "Electronics") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-electronic - title: Revenue (Electronic) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Home") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-home - title: Revenue (Home) - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE {label/products.category} - IN ("Outdoor") - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue-outdoor - title: Revenue (Outdoor) - - content: - format: $#,##0.0 - maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_customer - title: Revenue per Customer - - content: - format: $#,##0.0 - maql: SELECT {metric/revenue} / {metric/campaign_spend} - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_dollar_spent - title: Revenue per Dollar Spent - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10 - title: Revenue / Top 10 - - content: - format: $#,##0 - maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_top_10_percent - title: Revenue / Top 10% - - content: - format: $#,##0 - maql: SELECT {metric/revenue} BY ALL OTHER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue - title: Total Revenue - - content: - format: $#,##0 - maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: total_revenue-no_filters - title: Total Revenue (No Filters) - parameters: [] - visualizationObjects: - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: d319bcb2d8c04442a684e3b3cd063381 - title: Campaign Spend - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_channels.category - type: label - localIdentifier: 291c085e7df8420db84117ca49f59c49 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: d9dd143d647d4d148405a60ec2cf59bc - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: type - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_channels.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: campaign_spend - title: Campaign Spend - - content: - buckets: - - items: - - measure: - alias: Active Customers - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 - title: '# of Active Customers' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_customer - type: metric - localIdentifier: ec0606894b9f4897b7beaf1550608928 - title: Revenue per Customer - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 0de7d7f08af7480aa636857a26be72b6 - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -12 - granularity: GDC.time.month - to: -1 - properties: - controls: - colorMapping: - - color: - type: guid - value: '20' - id: 2ba0b87b59ca41a4b1530e81a5c1d081 - - color: - type: guid - value: '4' - id: ec0606894b9f4897b7beaf1550608928 - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - ec0606894b9f4897b7beaf1550608928 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: customers_trend - title: Customers Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_per_product - type: metric - localIdentifier: 08d8346c1ce7438994b251991c0fbf65 - title: '% Revenue per Product' - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: b2350c06688b4da9b3833ebcce65527f - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: 7a4045fd00ac44579f52406df679435f - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 6a003ffd14994237ba64c4a02c488429 - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 7a4045fd00ac44579f52406df679435f - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percent_revenue_per_product_by_customer_and_category - title: '% Revenue per Product by Customer and Category' - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_active_customers - type: metric - localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 - title: '# of Active Customers' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: region - type: label - localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: region - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - properties: - controls: - legend: - position: bottom - stackMeasuresToPercent: true - version: '2' - visualizationUrl: local:area - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: percentage_of_customers_by_region - title: Percentage of Customers by Region - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 590d332ef686468b8878ae41b23341c6 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: b166c71091864312a14c7ae8ff886ffe - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: e920a50e0bbb49788df0aac53634c1cd - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:treemap - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_breakdown - title: Product Breakdown - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: true - filters: [] - item: - identifier: - id: revenue - type: metric - format: '#,##0.00%' - localIdentifier: 162b857af49d45769bc12604a5c192b9 - title: '% Revenue' - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - legend: - position: bottom - version: '2' - visualizationUrl: local:donut - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_categories_pie_chart - title: Product Categories Pie Chart - - content: - buckets: - - items: - - measure: - alias: Previous Period - definition: - popMeasureDefinition: - measureIdentifier: c82e025fa2db4afea9a600a424591dbe - popAttribute: - identifier: - id: date.year - type: attribute - localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop - - measure: - alias: This Period - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: c82e025fa2db4afea9a600a424591dbe - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -11 - granularity: GDC.time.month - to: 0 - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - stackMeasures: false - xaxis: - name: - visible: false - yaxis: - name: - visible: false - version: '2' - visualizationUrl: local:column - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_revenue_comparison-over_previous_period - title: Product Revenue Comparison (over previous period) - - content: - buckets: - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 - title: '# of Orders' - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 - title: Revenue - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: d2a991bdd123448eb2be73d79f1180c4 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: - controls: - dataLabels: - visible: auto - grid: - enabled: true - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: product_saleability - title: Product Saleability - - content: - buckets: - - items: - - measure: - alias: Items Sold - definition: - measureDefinition: - aggregation: sum - filters: [] - item: - identifier: - id: quantity - type: fact - format: '#,##0.00' - localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 - title: Sum of Quantity - - measure: - definition: - measureDefinition: - aggregation: avg - filters: [] - item: - identifier: - id: price - type: fact - format: '#,##0.00' - localIdentifier: aa6391acccf1452f8011201aef9af492 - title: Avg Price - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: percent_revenue_in_category - type: metric - localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 - title: '% Revenue in Category' - - measure: - alias: Total Revenue - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 06bc6b3b9949466494e4f594c11f1bff - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: {} - sorts: - - attributeSortItem: - attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff - direction: asc - version: '2' - visualizationUrl: local:table - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_and_quantity_by_product_and_category - title: Revenue and Quantity by Product and Category - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 - localIdentifier: trend - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 - localIdentifier: segment - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - granularity: GDC.time.year - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:line - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_category_trend - title: Revenue by Category Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c - title: Revenue - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 - localIdentifier: view - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - properties: {} - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_by_product - title: Revenue by Product - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: campaign_spend - type: metric - localIdentifier: 13a50d811e474ac6808d8da7f4673b35 - title: Campaign Spend - localIdentifier: measures - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_per_dollar_spent - type: metric - localIdentifier: a0f15e82e6334280a44dbedc7d086e7c - title: Revenue per Dollar Spent - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: campaign_name - type: label - localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff - localIdentifier: attribute - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: campaign_name - type: label - notIn: - values: [] - properties: - controls: - xaxis: - min: '0' - yaxis: - min: '0' - version: '2' - visualizationUrl: local:scatter - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_per_usd_vs_spend_by_campaign - title: Revenue per $ vs Spend by Campaign - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: revenue - type: metric - localIdentifier: 60c854969a9c4c278ab596d99c222e92 - title: Revenue - localIdentifier: measures - - items: - - measure: - alias: Number of Orders - definition: - measureDefinition: - computeRatio: false - filters: [] - item: - identifier: - id: amount_of_orders - type: metric - localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 - title: '# of Orders' - localIdentifier: secondary_measures - - items: - - attribute: - displayForm: - identifier: - id: date.month - type: label - localIdentifier: 413ac374b65648fa96826ca01d47bdda - localIdentifier: view - filters: - - relativeDateFilter: - dataSet: - identifier: - id: date - type: dataset - from: -3 - granularity: GDC.time.quarter - to: 0 - properties: - controls: - dualAxis: true - legend: - position: bottom - primaryChartType: column - secondaryChartType: line - secondary_yaxis: - measures: - - c2fa7ef48cc54af99f8c280eb451e051 - xaxis: - name: - visible: false - rotation: auto - version: '2' - visualizationUrl: local:combo2 - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: revenue_trend - title: Revenue Trend - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: customer_name - type: label - localIdentifier: f4e39e24f11e4827a191c30d65c89d2c - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: state - type: label - localIdentifier: bbccd430176d428caed54c99afc9589e - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: customer_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: state - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_customers - title: Top 10 Customers - - content: - buckets: - - items: - - measure: - definition: - measureDefinition: - filters: [] - item: - identifier: - id: revenue_top_10 - type: metric - localIdentifier: 77dc71bbac92412bac5f94284a5919df - title: Revenue / Top 10 - localIdentifier: measures - - items: - - attribute: - displayForm: - identifier: - id: product_name - type: label - localIdentifier: 781952e728204dcf923142910cc22ae2 - localIdentifier: view - - items: - - attribute: - displayForm: - identifier: - id: products.category - type: label - localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 - localIdentifier: stack - filters: - - negativeAttributeFilter: - displayForm: - identifier: - id: product_name - type: label - notIn: - values: [] - - negativeAttributeFilter: - displayForm: - identifier: - id: products.category - type: label - notIn: - values: [] - properties: - controls: - legend: - position: bottom - version: '2' - visualizationUrl: local:bar - createdAt: 2000-01-01 00:00 - createdBy: - id: admin - type: user - id: top_10_products - title: Top 10 Products - ldm: - datasets: - - aggregatedFacts: [] - attributes: - - description: Campaign channel id - id: campaign_channel_id - isNullable: false - labels: [] - sourceColumn: campaign_channel_id - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Campaign channel id - - description: Category - id: campaign_channels.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Category - - description: Type - id: type - isNullable: true - labels: [] - sourceColumn: type - sourceColumnDataType: STRING - tags: - - Campaign channels - title: Type - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaign_channels - path: - - demo - - campaign_channels - type: dataSource - description: Campaign channels - facts: - - description: Budget - id: budget - isNullable: true - sourceColumn: budget - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Budget - - description: Spend - id: spend - isNullable: true - sourceColumn: spend - sourceColumnDataType: NUMERIC - tags: - - Campaign channels - title: Spend - grain: - - id: campaign_channel_id - type: attribute - id: campaign_channels - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - tags: - - Campaign channels - title: Campaign channels - - aggregatedFacts: - - description: Budget Agg - id: budget_agg - sourceColumn: budget - sourceColumnDataType: INT - sourceFactReference: - operation: SUM - reference: - id: budget - type: fact - tags: - - Campaign channels per category - attributes: [] - description: Campaign channels per categories - facts: [] - grain: [] - id: campaign_channels_per_category - precedence: 1 - references: - - identifier: - id: campaign_channels - type: dataset - multivalue: false - sources: - - column: campaign_channel_id - dataType: STRING - isNullable: true - target: - id: campaign_channel_id - type: attribute - sql: - dataSourceId: demo-test-ds - statement: SELECT category, SUM(budget) FROM campaign_channels - GROUP BY category - tags: - - Campaign channels per category - title: Campaign channels per category - - aggregatedFacts: [] - attributes: - - description: Campaign id - id: campaign_id - isNullable: false - labels: [] - sourceColumn: campaign_id - sourceColumnDataType: INT - tags: - - Campaigns - title: Campaign id - - description: Campaign name - id: campaign_name - isNullable: true - labels: [] - sourceColumn: campaign_name - sourceColumnDataType: STRING - tags: - - Campaigns - title: Campaign name - dataSourceTableId: - dataSourceId: demo-test-ds - id: campaigns - path: - - demo - - campaigns - type: dataSource - description: Campaigns - facts: [] - grain: - - id: campaign_id - type: attribute - id: campaigns - references: [] - tags: - - Campaigns - title: Campaigns - - aggregatedFacts: [] - attributes: - - description: Customer id - id: customer_id - isNullable: false - labels: [] - sourceColumn: customer_id - sourceColumnDataType: INT - tags: - - Customers - title: Customer id - - description: Customer name - id: customer_name - isNullable: true - labels: [] - sourceColumn: customer_name - sourceColumnDataType: STRING - tags: - - Customers - title: Customer name - - description: Region - id: region - isNullable: true - labels: [] - sourceColumn: region - sourceColumnDataType: STRING - tags: - - Customers - title: Region - - description: State - id: state - isNullable: true - labels: - - description: Location - id: geo__state__location - isNullable: true - sourceColumn: geo__state__location - sourceColumnDataType: STRING - tags: - - Customers - title: Location - valueType: GEO - sourceColumn: state - sourceColumnDataType: STRING - tags: - - Customers - title: State - dataSourceTableId: - dataSourceId: demo-test-ds - id: customers - path: - - demo - - customers - type: dataSource - description: Customers - facts: [] - grain: - - id: customer_id - type: attribute - id: customers - references: [] - tags: - - Customers - title: Customers - - aggregatedFacts: [] - attributes: - - description: Order id - id: order_id - isNullable: true - labels: [] - sourceColumn: order_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order id - - description: Order line id - id: order_line_id - isNullable: false - labels: [] - sourceColumn: order_line_id - sourceColumnDataType: STRING - tags: - - Order lines - title: Order line id - - description: Order status - id: order_status - isNullable: true - labels: [] - sourceColumn: order_status - sourceColumnDataType: STRING - tags: - - Order lines - title: Order status - dataSourceTableId: - dataSourceId: demo-test-ds - id: order_lines - path: - - demo - - order_lines - type: dataSource - description: Order lines - facts: - - description: Price - id: price - isNullable: true - sourceColumn: price - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Price - - description: Quantity - id: quantity - isNullable: true - sourceColumn: quantity - sourceColumnDataType: NUMERIC - tags: - - Order lines - title: Quantity - grain: - - id: order_line_id - type: attribute - id: order_lines - references: - - identifier: - id: campaigns - type: dataset - multivalue: false - sources: - - column: campaign_id - dataType: INT - isNullable: true - target: - id: campaign_id - type: attribute - - identifier: - id: customers - type: dataset - multivalue: false - sources: - - column: customer_id - dataType: INT - isNullable: true - target: - id: customer_id - type: attribute - - identifier: - id: date - type: dataset - multivalue: false - sources: - - column: date - dataType: DATE - isNullable: true - target: - id: date - type: date - - identifier: - id: products - type: dataset - multivalue: false - sources: - - column: product_id - dataType: INT - isNullable: true - target: - id: product_id - type: attribute - tags: - - Order lines - title: Order lines - workspaceDataFilterColumns: - - dataType: STRING - name: wdf__region - - dataType: STRING - name: wdf__state - workspaceDataFilterReferences: - - filterColumn: wdf__region - filterColumnDataType: STRING - filterId: - id: wdf__region - type: workspaceDataFilter - - aggregatedFacts: [] - attributes: - - description: Product id - id: product_id - isNullable: false - labels: [] - sourceColumn: product_id - sourceColumnDataType: INT - tags: - - Products - title: Product id - - description: Product name - id: product_name - isNullable: true - labels: [] - sourceColumn: product_name - sourceColumnDataType: STRING - tags: - - Products - title: Product name - - description: Category - id: products.category - isNullable: true - labels: [] - sourceColumn: category - sourceColumnDataType: STRING - tags: - - Products - title: Category - dataSourceTableId: - dataSourceId: demo-test-ds - id: products - path: - - demo - - products - type: dataSource - description: Products - facts: [] - grain: - - id: product_id - type: attribute - id: products - references: [] - tags: - - Products - title: Products - dateInstances: - - description: '' - granularities: - - DAY - - WEEK - - MONTH - - QUARTER - - YEAR - granularitiesFormatting: - titleBase: '' - titlePattern: '%titleBase - %granularityTitle' - id: date - tags: - - Date - title: Date - name: Demo - permissions: - - assignee: - id: demo2 - type: user - name: ANALYZE - - assignee: - id: demoGroup - type: userGroup - name: VIEW - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west - model: - analytics: - analyticalDashboardExtensions: - - id: campaign - permissions: - - assigneeRule: - type: allWorkspaceUsers - name: VIEW - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasetExtensions: - - id: order_lines - workspaceDataFilterReferences: - - filterColumn: wdf__state - filterColumnDataType: STRING - filterId: - id: wdf__state - type: workspaceDataFilter - datasets: [] - dateInstances: [] - name: Demo West - parent: - id: demo - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - - automations: [] - customApplicationSettings: [] - filterViews: [] - hierarchyPermissions: [] - id: demo_west_california - model: - analytics: - analyticalDashboardExtensions: [] - analyticalDashboards: [] - attributeHierarchies: [] - dashboardPlugins: [] - exportDefinitions: [] - filterContexts: [] - memoryItems: [] - metrics: [] - parameters: [] - visualizationObjects: [] - ldm: - datasets: [] - dateInstances: [] - name: Demo West California - parent: - id: demo_west - type: workspace - permissions: [] - settings: [] - userDataFilters: [] - headers: - Accept-Encoding: - - br, gzip, deflate - Content-Type: - - application/json - X-GDC-VALIDATE-RELATIONS: - - 'true' - X-Requested-With: - - XMLHttpRequest - method: PUT - uri: http://localhost:3000/api/v1/layout/organization - response: - body: - string: - detail: 'Invalid combination of auth properties. Only none, user + password, - token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, - user: , password: , token: , key-pair: , clientId: , - clientSecret: ' - status: 400 - title: Bad Request - traceId: NORMALIZED_TRACE_ID_000000000000 - headers: - Content-Type: - - application/problem+json - DATE: *id001 - Expires: - - '0' - Pragma: - - no-cache - X-Content-Type-Options: - - nosniff - X-GDC-TRACE-ID: *id001 - status: - code: 400 - message: Bad Request -version: 1 diff --git a/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py b/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py index 119eb8f92..26f524b78 100644 --- a/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py +++ b/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py @@ -578,10 +578,10 @@ def test_layout_ip_allowlist_policies(test_config): id="admin-vpn-only", allowed_sources=["203.0.113.10/32", "198.51.100.0/24"], user_groups=[ - CatalogDeclarativeUserGroupIdentifier(id="group.admins", type="userGroup"), + CatalogDeclarativeUserGroupIdentifier(id="adminGroup", type="userGroup"), ], users=[ - CatalogUserIdentifier(id="employee123", type="user"), + CatalogUserIdentifier(id="demo", type="user"), ], ), ] @@ -593,8 +593,8 @@ def test_layout_ip_allowlist_policies(test_config): assert result[0].id == "admin-vpn-only" assert result[0].allowed_sources == ["203.0.113.10/32", "198.51.100.0/24"] assert len(result[0].user_groups) == 1 - assert result[0].user_groups[0].id == "group.admins" + assert result[0].user_groups[0].id == "adminGroup" assert len(result[0].users) == 1 - assert result[0].users[0].id == "employee123" + assert result[0].users[0].id == "demo" finally: sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies) diff --git a/transcripts/fix-C009-attempt1.jsonl b/transcripts/fix-C009-attempt1.jsonl deleted file mode 100644 index 73d749da3..000000000 --- a/transcripts/fix-C009-attempt1.jsonl +++ /dev/null @@ -1,127 +0,0 @@ -{"ts": 1778572545.4825163, "type": "system"} -{"ts": 1778572553.9514349, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me analyze the failing test and understand what's going wrong. The test `test_layout_ip_allowlist_policies` is failing with a 400 Bad Request error during the teardown/restore phase. Let me read the relevant files to understand the issue.\n\nThe error messages in the pytest output are:\n1. First error: `'users' entities do not exist. Not existing IDs: [Identifier(employee123)/Organization(python-sdk-dex)]` - This seems to be related to user validation in the IP allowlist policy\n2. Second error: `Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. \n\nThe second error happens during `put_declarative_ip_allowlist_policies` which calls `set_organization_layout`. The error is about datasource auth properties, which suggests that when we read and write back the organization layout, we're somehow corrupting the datasource configuration. Specifically, the \"demo-test-ds\" datasource is being restored with invalid auth properties\u2014likely a user without a password\u2014which violates the allowed auth combinations.\n\nThis is a classic read-modify-write problem where sensitive fields like passwords get redacted by the API for security, and when we write them back as null or empty, the validation fails.", "truncated": false}]} -{"ts": 1778572553.971637, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01QF9yuxhFAV7Yx2A7Xfg1tA", "input": "{\"file_path\": \"/home/user/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 50}", "truncated": false}]} -{"ts": 1778572554.2598937, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QF9yuxhFAV7Yx2A7Xfg1tA", "is_error": true, "content": "File does not exist. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} -{"ts": 1778572554.2612257, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01PX7FRLn3ovnbFv1PVm4ef6", "input": "{\"file_path\": \"/home/user/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 570, \"limit\": 80}", "truncated": false}]} -{"ts": 1778572554.2953153, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01PX7FRLn3ovnbFv1PVm4ef6", "is_error": true, "content": "File does not exist. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} -{"ts": 1778572556.6449418, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01CUkLHfVURosRfxeTjvfR8p", "input": "{\"command\": \"find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \\\"service.py\\\" -path \\\"*/organization/*\\\" 2>/dev/null\", \"description\": \"Find organization service.py path\"}", "truncated": false}]} -{"ts": 1778572556.6509285, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CUkLHfVURosRfxeTjvfR8p", "is_error": true, "content": "Blocked: find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \"service.py\" -path \"*/organiza", "truncated": false}]} -{"ts": 1778572556.8917181, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01QXCoPyz5TcEB5sC84TaQaD", "input": "{\"command\": \"find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \\\"test_catalog_organization.py\\\" 2>/dev/null\", \"description\": \"Find test file path\"}", "truncated": false}]} -{"ts": 1778572556.9422717, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QXCoPyz5TcEB5sC84TaQaD", "is_error": true, "content": "Blocked: find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \"test_catalog_organization.py\"", "truncated": false}]} -{"ts": 1778572558.987669, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LaCezsuQF8jbuQe3NzWQ2o", "input": "{\"pattern\": \"packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\"}", "truncated": false}]} -{"ts": 1778572559.042493, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LaCezsuQF8jbuQe3NzWQ2o", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py", "truncated": false}]} -{"ts": 1778572559.04287, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01MbEaWCwJrHwSqb7gCJ7Sqy", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\"}", "truncated": false}]} -{"ts": 1778572559.0787725, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MbEaWCwJrHwSqb7gCJ7Sqy", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/test_catalog_organization.py", "truncated": false}]} -{"ts": 1778572561.175191, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GHpK2ms6JGqEL3LYdrhByi", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 60}", "truncated": false}]} -{"ts": 1778572561.5280778, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GHpK2ms6JGqEL3LYdrhByi", "is_error": false, "content": "750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} -{"ts": 1778572561.855271, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DCyTvZ3XB64Gy2ufyZw7qr", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 565, \"limit\": 80}", "truncated": false}]} -{"ts": 1778572561.887425, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DCyTvZ3XB64Gy2ufyZw7qr", "is_error": false, "content": "565\t# sdk.catalog_organization.put_declarative_identity_providers([])\n566\t# idps = sdk.catalog_organization.get_declarative_identity_providers()\n567\t# assert len(idps) == 0\n568\t\n569\t\n570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"group.admins\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"employee123\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"group.admins\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"employee123\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} -{"ts": 1778572571.458231, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the issue. The test uses `gd_vcr.use_cassette` to record/replay API calls, but the cassette file doesn't exist yet. So when the test runs live against a real server, it fails because:\n\n1. The `put_declarative_ip_allowlist_policies` with `new_policies` that contain `employee123` user fails with \"users entities do not exist\" (the employee123 user doesn't exist in the test org).\n\n2. The fallback `put_declarative_ip_allowlist_policies(original_policies)` in the `finally` block also fails because the read-modify-write approach is problematic - when we read the org layout and write it back, sensitive datasource credentials are stripped by the API, and when we PUT them back without the password, the API rejects it with \"Invalid combination of auth properties\".\n\n\nThe real problem is that the read-modify-write pattern for restoring the original policies doesn't work\u2014reading the organization layout strips sensitive fields like datasource passwords, so when we PUT the layout back without those credentials, the API rejects it as invalid.\n\nBut wait, this test uses VCR cassettes for replaying recorded API interactions, so it shouldn't be hitting the real API at all. Let me check if the cassette file actually exists.", "truncated": false}]} -{"ts": 1778572571.4630764, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01JDTxQDtmtE9mh5DeHRF3h5", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/fixtures/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} -{"ts": 1778572571.7129104, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JDTxQDtmtE9mh5DeHRF3h5", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778572571.7146492, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01DM4hX8L6n7oKNNgiww13aC", "input": "{\"command\": \"ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/ | grep -i ip 2>/dev/null || echo \\\"no ip-related fixtures\\\"\", \"description\": \"Check if cassette file exists\"}", "truncated": false}]} -{"ts": 1778572571.8027024, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DM4hX8L6n7oKNNgiww13aC", "is_error": true, "content": "Blocked: ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fi", "truncated": false}]} -{"ts": 1778572573.494986, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01VjDhFFa24n74CWm46My2SM", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/catalog/fixtures/*.yaml\"}", "truncated": false}]} -{"ts": 1778572573.5250852, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01VjDhFFa24n74CWm46My2SM", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778572575.964956, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Ao1HHXBxAA2xdpjyhjcdWW", "input": "{\"pattern\": \"packages/gooddata-sdk/tests/**/*.yaml\"}", "truncated": false}]} -{"ts": 1778572575.9876597, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ao1HHXBxAA2xdpjyhjcdWW", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/config/test_translate.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/bigquery.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_cache_strategy.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_data_sources_list.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_delete_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_generate_logical_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_generate_logical_model_sql_datasets.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_load_and_put_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_put_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_put_declarative_data_sources_connection.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_register_upload_notification.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_pdm_and_generate_logical_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_pdm_and_generate_logical_model_sql_datasets.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_scan_schemata.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_store_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_declarative_data_sources.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model_with_schemata.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/demo_test_scan_model_with_table_prefix.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/dremio.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/patch.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/data_sources/redshift.yam", "truncated": true}]} -{"ts": 1778572578.5829642, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette file `packages/gooddata-sdk/tests/catalog/fixtures/layout_ip_allowlist_policies.yaml` doesn't exist. The test references `_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"` - let me check where `_fixtures_dir` points to.\n\nLet me also look at how similar tests set up cassette paths to understand what's expected.", "truncated": false}]} -{"ts": 1778572579.5264392, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018sNQAbdPbq7LpWPn15QDNz", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 1, \"limit\": 40}", "truncated": false}]} -{"ts": 1778572579.5604656, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018sNQAbdPbq7LpWPn15QDNz", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\tfrom pathlib import Path\n5\t\n6\tfrom gooddata_api_client.exceptions import NotFoundException\n7\tfrom gooddata_sdk import (\n8\t CatalogCspDirective,\n9\t CatalogDeclarativeIpAllowlistPolicy,\n10\t CatalogDeclarativeNotificationChannel,\n11\t CatalogJwk,\n12\t CatalogOrganization,\n13\t CatalogOrganizationSetting,\n14\t CatalogRsaSpecification,\n15\t CatalogWebhook,\n16\t GoodDataSdk,\n17\t)\n18\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n19\tfrom tests_support.vcrpy_utils import get_vcr\n20\t\n21\tfrom .conftest import safe_delete\n22\t\n23\tgd_vcr = get_vcr()\n24\t\n25\t_default_jwk_id = \"demoJwk\"\n26\t_current_dir = Path(__file__).parent.absolute()\n27\t_fixtures_dir = _current_dir / \"fixtures\" / \"organization\"\n28\t\n29\t\n30\tdef _default_organization_check(organization: CatalogOrganization, test_config: dict):\n31\t # Relaxed assertions \u2014 cassettes may come from local or staging environment,\n32\t # so we only verify the fields are populated, not their exact values.\n33\t assert organization.id\n34\t assert organization.attributes.name\n35\t assert organization.attributes.hostname\n36\t\n37\t\n38\tdef _default_jwk(jwk_id=_default_jwk_id, alg=None, kid=None):\n39\t rsa_specification = CatalogRsaSpecification(\n40\t alg=alg if alg else \"RS256\",", "truncated": false}]} -{"ts": 1778572620.037761, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The `_fixtures_dir` is set to `_current_dir / \"fixtures\" / \"organization\"`, which would be `packages/gooddata-sdk/tests/catalog/fixtures/organization/`. \n\nThe cassette file at `tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml` does NOT exist yet. The ground rules say: \"Do NOT fabricate cassette YAML files \u2014 they will be re-recorded by the pipeline after you finish. Stale cassettes were already deleted.\"\n\nSo the cassette doesn't exist, which means the test is running in \"record\" mode against a live server. The test is failing because:\n\n\nThe first `put_declarative_ip_allowlist_policies(new_policies)` call fails since `employee123` doesn't exist on the server, and the cleanup in the finally block also fails when trying to restore the original policies \u2014 the read returns redacted datasource configs that fail validation on PUT. The real issue is that the test assumes a user that doesn't exist in the environment, and the read-modify-write pattern breaks when the API redacts sensitive fields. Once the cassettes are recorded by the pipeline, this test should pass since it'll replay the recorded responses instead of hitting the live server.\n\nBut I'm realizing the test itself has fundamental problems that would prevent it from recording in the first place. The `employee123` user doesn't exist, so the initial PUT fails immediately. And even if that worked, the cleanup would fail because restoring the original policies hits the auth validation issue with redacted fields. I need to fix the test code itself \u2014 either remove the non-existent user from the policy or swap it for a real user that exists in the test environment, and I need to rethink how the restore logic handles the read-modify-write pattern when sensitive fields get redacted. The instructions are clear\u2014I need to fix only what's necessary for the tests to pass, not redesign the whole approach. The cassette needs to be re-recorded, and there are two issues blocking that: the test references a non-e", "truncated": true}]} -{"ts": 1778572620.0597582, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the API client to check if there's a dedicated endpoint for IP allowlist policies:", "truncated": false}]} -{"ts": 1778572620.066379, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0184RFKAgTbVHcZYRxVdLhyp", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} -{"ts": 1778572620.0687513, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01XGuicks9JZ7yj1x5dsPTvm", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py\"}", "truncated": false}]} -{"ts": 1778572620.0697641, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0184RFKAgTbVHcZYRxVdLhyp", "is_error": true, "content": "Path does not exist: /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} -{"ts": 1778572620.0972176, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XGuicks9JZ7yj1x5dsPTvm", "is_error": false, "content": "1\t# (C) 2025 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\t\n6\tfrom attrs import define, field\n7\tfrom gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n8\t\n9\tfrom gooddata_sdk.catalog.base import Base\n10\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n11\t\n12\t\n13\t@define(kw_only=True)\n14\tclass CatalogDeclarativeIpAllowlistPolicy(Base):\n15\t id: str\n16\t allowed_sources: list[str] = field(factory=list)\n17\t user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list)\n18\t users: list[CatalogUserIdentifier] = field(factory=list)\n19\t\n20\t @staticmethod\n21\t def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]:\n22\t return DeclarativeIpAllowlistPolicy\n23\t", "truncated": false}]} -{"ts": 1778572622.0756288, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HRLih28n3J9dFoGSbmM4nf", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} -{"ts": 1778572622.106803, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HRLih28n3J9dFoGSbmM4nf", "is_error": false, "content": "Found 9 files\ngooddata-api-client/gooddata_api_client/models/__init__.py\ngooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py\ngooddata-api-client/docs/LayoutApi.md\ngooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md\ngooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md\ngooddata-api-client/docs/DeclarativeOrganization.md\ngooddata-api-client/.openapi-generator/FILES\ngooddata-api-client/README.md", "truncated": false}]} -{"ts": 1778572624.3948033, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DZuYQZ299j9yUjx1XW9TDx", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/docs/LayoutApi.md\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572624.7454011, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DZuYQZ299j9yUjx1XW9TDx", "is_error": false, "content": "4438: ip_allowlist_policies=[\n4439: DeclarativeIpAllowlistPolicy(", "truncated": false}]} -{"ts": 1778572624.8203256, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01CKubJVPFqgxbGkjuRM6tX1", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist|ipAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572624.853468, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CKubJVPFqgxbGkjuRM6tX1", "is_error": false, "content": "585: ip_allowlist_policies=[\n586: DeclarativeIpAllowlistPolicy(", "truncated": false}]} -{"ts": 1778572626.9111085, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01WWNiZUnGdcKDfAAnuAhh2M", "input": "{\"pattern\": \"ip_allowlist_polic\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} -{"ts": 1778572626.943843, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WWNiZUnGdcKDfAAnuAhh2M", "is_error": false, "content": "Found 2 files\ngooddata-api-client/gooddata_api_client/models/__init__.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py", "truncated": false}]} -{"ts": 1778572631.0610168, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So there's no dedicated endpoint for IP allowlist policies in the API client. The IP allowlist policies are part of the `DeclarativeOrganization` model. So the read-modify-write approach is the only way.\n\nThe problem is:\n1. The test uses `employee123` user which doesn't exist in the staging environment\n2. The read-modify-write approach fails because the GET response redacts sensitive datasource credentials, and the PUT back fails validation\n\nLet me look at how the `OrganizationDeclarativeAPIsApi` handles these...\n\nLet me check if there's a `put_organization_layout` or similar operation in that API:", "truncated": false}]} -{"ts": 1778572631.7908683, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_017xb7V6HS2XyBkrTCR1SrBo", "input": "{\"pattern\": \"def.*organization_layout|organization_layout.*def\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} -{"ts": 1778572631.8303072, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017xb7V6HS2XyBkrTCR1SrBo", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:479: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:724: def set_organization_layout(\ngooddata-api-client/gooddata_api_client/api/layout_api.py:3550: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/layout_api.py:5870: def set_organization_layout(", "truncated": false}]} -{"ts": 1778572633.7254303, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DoYdf4g3jsyHtzGvbLwY3H", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} -{"ts": 1778572633.7762916, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DoYdf4g3jsyHtzGvbLwY3H", "is_error": false, "content": "1\t\"\"\"\n2\t OpenAPI definition\n3\t\n4\t No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501\n5\t\n6\t The version of the OpenAPI document: v0\n7\t Contact: support@gooddata.com\n8\t Generated by: https://openapi-generator.tech\n9\t\"\"\"\n10\t\n11\t\n12\timport re # noqa: F401\n13\timport sys # noqa: F401\n14\t\n15\tfrom gooddata_api_client.model_utils import ( # noqa: F401\n16\t ApiTypeError,\n17\t ModelComposed,\n18\t ModelNormal,\n19\t ModelSimple,\n20\t cached_property,\n21\t change_keys_js_to_python,\n22\t convert_js_args_to_python_args,\n23\t date,\n24\t datetime,\n25\t file_type,\n26\t none_type,\n27\t validate_get_composed_info,\n28\t OpenApiModel\n29\t)\n30\tfrom gooddata_api_client.exceptions import ApiAttributeError\n31\t\n32\t\n33\tdef lazy_import():\n34\t from gooddata_api_client.model.declarative_agent import DeclarativeAgent\n35\t from gooddata_api_client.model.declarative_custom_geo_collection import DeclarativeCustomGeoCollection\n36\t from gooddata_api_client.model.declarative_data_source import DeclarativeDataSource\n37\t from gooddata_api_client.model.declarative_export_template import DeclarativeExportTemplate\n38\t from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider\n39\t from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n40\t from gooddata_api_client.model.declarative_jwk import DeclarativeJwk\n41\t from gooddata_api_client.model.declarative_notification_channel import DeclarativeNotificationChannel\n42\t from gooddata_api_client.model.declarative_organization_info import DeclarativeOrganizationInfo\n43\t from gooddata_api_client.model.declarative_user import DeclarativeUser\n44\t from gooddata_api_client.model.declarative_user_group import DeclarativeUserGroup\n45\t from gooddata_api_client.model.declarative_workspace import DeclarativeWorkspace\n46\t from gooddata_api_client.mode", "truncated": true}]} -{"ts": 1778572650.682085, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the structure. Let me think about the root cause of the failures:\n\n**Issue 1**: `employee123` user doesn't exist in the staging environment\n**Issue 2**: Read-modify-write approach corrupts datasource auth (returns redacted password in GET, then PUT fails due to missing password)\n\nNow, Issue 2 is the one that's actually crashing the test (in the `finally` block). Issue 1 caused the exception that led to the finally block executing.\n\nThe key question is: what's the right fix here?\n\nLooking at the structure of the problem:\n- The `put_declarative_ip_allowlist_policies` does a full GET of org layout, modifies ip_allowlist_policies, then PUTs the whole thing back\n\n\n- During a live test against staging, the GET returns a datasource with `user: , password: ` (because password is redacted)\n- The PUT then fails because the API requires either both user+password or neither\n\nThis is a fundamental design flaw in the read-modify-write approach for the `put_declarative_ip_allowlist_policies` implementation. The test uses `gd_vcr.use_cassette` to capture and replay HTTP traffic, so once cassettes are recorded, subsequent runs just replay from them. But the cassette file doesn't exist yet, so we need the test to pass during the initial recording phase.\n\nThe instructions say stale cassettes were already deleted and not to fabricate cassette YAML files\u2014they'll be re-recorded by the pipeline. So the real issue is that if the test fails during recording, the cassette won't be created and it'll fail forever. I'm wondering if there's a way to limit what `set_organization_layout` modifies or maybe clear the problematic datasource from the org layout before the PUT, though that feels too invasive. Let me look more closely at the actual error to find a better solution.\n\nThe datasource `demo-test-ds` has a user set but no password, which happens because the GET response redacts passwords. When the PUT sends back the full org layout, the API rejects this invalid auth ", "truncated": true}]} -{"ts": 1778572650.7663822, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HZ9eLeyTMk7UtkSma1w26e", "input": "{\"pattern\": \"put_declarative_notification_channels|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572650.8019989, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HZ9eLeyTMk7UtkSma1w26e", "is_error": false, "content": "647: def put_declarative_notification_channels(\n777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} -{"ts": 1778572652.5978413, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_016jLtpAGwfCcAHkxXyKy6me", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 640, \"limit\": 50}", "truncated": false}]} -{"ts": 1778572652.8133125, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016jLtpAGwfCcAHkxXyKy6me", "is_error": false, "content": "640\t List of declarative notification channels.\n641\t \"\"\"\n642\t return [\n643\t CatalogDeclarativeNotificationChannel.from_api(nc)\n644\t for nc in self._layout_api.get_notification_channels_layout().notification_channels\n645\t ]\n646\t\n647\t def put_declarative_notification_channels(\n648\t self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n649\t ) -> None:\n650\t \"\"\"\n651\t Put declarative notification channels in the current organization.\n652\t\n653\t Args:\n654\t notification_channels (list[CatalogDeclarativeNotificationChannel]):\n655\t List of declarative notification channels.\n656\t\n657\t Returns:\n658\t None\n659\t \"\"\"\n660\t api_ncs = [nc.to_api() for nc in notification_channels]\n661\t self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n662\t\n663\t def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:\n664\t \"\"\"\n665\t Get all declarative identity providers in the current organization.\n666\t\n667\t Returns:\n668\t list[CatalogDeclarativeIdentityProvider]:\n669\t List of declarative identity providers.\n670\t \"\"\"\n671\t return [\n672\t CatalogDeclarativeIdentityProvider.from_api(idp) for idp in self._layout_api.get_identity_providers_layout()\n673\t ]\n674\t\n675\t def put_declarative_identity_providers(self, identity_providers: list[CatalogDeclarativeIdentityProvider]) -> None:\n676\t \"\"\"\n677\t Put declarative identity providers in the current organization.\n678\t\n679\t Args:\n680\t identity_providers (list[CatalogDeclarativeIdentityProvider]):\n681\t List of declarative identity providers.\n682\t\n683\t Returns:\n684\t None\n685\t \"\"\"\n686\t api_idps = [idp.to_api() for idp in identity_providers]\n687\t ", "truncated": true}]} -{"ts": 1778572658.1518195, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! `put_declarative_notification_channels` uses `set_notification_channels` - a *dedicated* endpoint! It doesn't use `set_organization_layout`. Similarly, `put_declarative_identity_providers` uses `set_identity_providers`. \n\nThe prior agent used `set_organization_layout` (read-modify-write) because they thought there was no dedicated endpoint. But let me check if there's a dedicated endpoint for IP allowlist policies in the API client that the prior agent might have missed.\n\nWait, looking at the IP allowlist policies error and the API structure - the prior agent's decision said \"The OpenAPI spec has no dedicated /layout/ipAllowlistPolicies endpoint\". \n\nLet me scan through the available API methods to see if I'm missing a dedicated endpoint for IP allowlist policies.", "truncated": false}]} -{"ts": 1778572658.1547806, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the layout API for any IP allowlist specific endpoints:", "truncated": false}]} -{"ts": 1778572658.5095408, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01LZYcYcL2SCponyFS5umLdz", "input": "{\"command\": \"grep -n \\\"def.*ip\\\\|def.*allowlist\\\\|def.*allow_list\\\\|ip_allowlist\\\\|allowlist\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py 2>/dev/null | head -30\", \"description\": \"Search for IP allowlist methods in layout API\"}", "truncated": false}]} -{"ts": 1778572658.543462, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LZYcYcL2SCponyFS5umLdz", "is_error": true, "content": "Blocked: grep -n \"def.*ip\\|def.*allowlist\\|def.*allow_list\\|ip_allowlist\\|allowlist\" /hom", "truncated": false}]} -{"ts": 1778572660.6904714, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01MEHem5p99BnLt6MK3Rqhya", "input": "{\"pattern\": \"ip_allowlist|allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572660.7279794, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MEHem5p99BnLt6MK3Rqhya", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778572662.7213016, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0131L3RWsspdhSazy5Dso444", "input": "{\"pattern\": \"ip_allowlist|allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572662.7578123, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0131L3RWsspdhSazy5Dso444", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778572686.3569317, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Confirmed: there's no dedicated endpoint for IP allowlist policies in the API. The only way to update them is through the full org layout `set_organization_layout`.\n\nNow the problem is clear: the read-modify-write approach via `set_organization_layout` fails because the GET response redacts datasource credentials, and the PUT back fails because the API requires complete credentials.\n\nThe solution needs to be in either:\n1. The test (which is under `tests/`) - Fix the test to avoid triggering the issue\n2. The implementation (which is in `src/`) - Fix the read-modify-write to not corrupt auth\n\n\nI'm checking how other tests handle `get_organization_layout` to see if any attempt a read-modify-write pattern. Notification channels and identity providers have their own dedicated endpoints, so they avoid this problem entirely. IP allowlist policies are unique in being locked behind the full org layout endpoint. Let me explore whether using the OrganizationDeclarativeAPIsApi instead of LayoutApi could provide a workaround.\n\nActually, both APIs expose the same `get_organization_layout` and `set_organization_layout` methods, so switching APIs won't help. I'm considering whether I could strip out problematic datasources before writing the layout back, but that would delete them entirely\u2014not acceptable. The API doesn't support partial updates either. Looking at the test itself, the first `put` fails because `employee123` doesn't exist in the test org, and I need to figure out what happens in the finally block.\n\nThe core issue is that when I read the org layout, datasource passwords come back redacted, so when I try to write it back, the API rejects the incomplete credentials. I'm wondering if this read-modify-write pattern breaks all operations using `set_organization_layout`, or if it's specific to this test. Let me trace through what's actually happening: the first `put_declarative_ip_allowlist_policies` call modifies the org layout by adding IP allowlist policies with `employe", "truncated": true}]} -{"ts": 1778572686.359743, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how the full org layout is used in other tests and how datasource auth is handled:", "truncated": false}]} -{"ts": 1778572686.497629, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01QGaecwvGQXwGHAkKsRaCoX", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} -{"ts": 1778572686.5297132, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QGaecwvGQXwGHAkKsRaCoX", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} -{"ts": 1778572688.9217331, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01JkJSPaEQWYvfeXP2NEEbsA", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\", \"output_mode\": \"content\", \"glob\": \"*.py\"}", "truncated": false}]} -{"ts": 1778572689.0322008, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JkJSPaEQWYvfeXP2NEEbsA", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:125: self.get_organization_layout_endpoint = _Endpoint(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:130: 'operation_id': 'get_organization_layout',\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:274: self.set_organization_layout_endpoint = _Endpoint(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:279: 'operation_id': 'set_organization_layout',\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:479: def get_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:489: >>> thread = api.get_organization_layout(async_req=True)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:556: return self.get_organization_layout_endpoint.call_with_http_info(**kwargs)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:724: def set_organization_layout(\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:735: >>> thread = api.set_organization_layout(declarative_organization, async_req=True)\ngooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py:805: return self.set_organization_layout_endpoint.call_with_http_info(**kwargs)\ngooddata-api-client/gooddata_api_clien", "truncated": true}]} -{"ts": 1778572698.21292, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the situation clearly. There's no dedicated endpoint for IP allowlist policies. The only way to set them is via `set_organization_layout`. The read-modify-write approach is the only option.\n\nThe problem is that when the org layout is read, sensitive datasource credentials are redacted. When we write the full org layout back, the API rejects it because the datasource has `user` set but `password` not set.\n\nNow, the real question is: is this something we need to handle in the `put_declarative_ip_allowlist_policies` implementation, or is this something that the test should handle differently?\n\n\nThe cassette-based test approach means once recordings are created, they'll replay without hitting the live server. But to generate those cassettes initially, the test needs to pass against the actual API, which requires either creating the `employee123` user in setup or removing it from the test policy, and also resolving the datasource authentication issue that prevents round-tripping the full org layout.\n\nNow I'm checking how the staging environment's conftest.py handles the snapshot mechanism to understand if there's a way around these constraints.", "truncated": false}]} -{"ts": 1778572698.213881, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest and how similar tests handle read-modify-write patterns:", "truncated": false}]} -{"ts": 1778572698.2323081, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01CVTWAaSanYARtWphAGE843", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 280, \"limit\": 40}", "truncated": false}]} -{"ts": 1778572698.422636, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CVTWAaSanYARtWphAGE843", "is_error": false, "content": "280\t except Exception as e:\n281\t logger.error(f\"Snapshot capture failed [workspace list for permissions]: {e}\")\n282\t snapshot[\"ws_permissions\"] = ws_permissions\n283\t\n284\t logger.info(\"Session snapshot captured\")\n285\t\n286\t # --- Tests run ---\n287\t yield snapshot\n288\t\n289\t # --- Restore (only if failures) ---\n290\t if not _session_has_failures:\n291\t logger.info(\"All tests passed \u2014 skipping session restore\")\n292\t return\n293\t\n294\t logger.warning(\"Test failures detected \u2014 restoring session snapshot...\")\n295\t\n296\t # Restore order matters: users/groups \u2192 data sources \u2192 workspaces \u2192\n297\t # workspace data filters \u2192 org permissions \u2192 notification channels \u2192\n298\t # per-workspace permissions\n299\t\n300\t if \"users_groups\" in snapshot:\n301\t try:\n302\t sdk.catalog_user.put_declarative_users_user_groups(snapshot[\"users_groups\"])\n303\t logger.info(\"Restored [users_groups]\")\n304\t except Exception as e:\n305\t logger.error(f\"RESTORE FAILED [users_groups]: {e}\")\n306\t\n307\t if \"data_sources\" in snapshot:\n308\t try:\n309\t sdk.catalog_data_source.put_declarative_data_sources(snapshot[\"data_sources\"], _credentials_path)\n310\t logger.info(\"Restored [data_sources]\")\n311\t except Exception as e:\n312\t logger.error(f\"RESTORE FAILED [data_sources]: {e}\")\n313\t\n314\t if \"workspaces\" in snapshot:\n315\t try:\n316\t sdk.catalog_workspace.put_declarative_workspaces(snapshot[\"workspaces\"])\n317\t logger.info(\"Restored [workspaces]\")\n318\t except Exception as e:\n319\t logger.error(f\"RESTORE FAILED [workspaces]: {e}\")", "truncated": false}]} -{"ts": 1778572698.4249816, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_013Z982nL8tgf84A3ANRFJxY", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_notification_channels.yaml\", \"offset\": 1, \"limit\": 60}", "truncated": false}]} -{"ts": 1778572698.4610713, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_013Z982nL8tgf84A3ANRFJxY", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\tinteractions:\n3\t - request:\n4\t body:\n5\t notificationChannels:\n6\t - allowedRecipients: CREATOR\n7\t customDashboardUrl: https://dashboard.site\n8\t destination:\n9\t token: '123'\n10\t type: WEBHOOK\n11\t url: https://webhook.site\n12\t id: webhook\n13\t name: Webhook\n14\t headers:\n15\t Accept-Encoding:\n16\t - br, gzip, deflate\n17\t Content-Type:\n18\t - application/json\n19\t X-GDC-VALIDATE-RELATIONS:\n20\t - 'true'\n21\t X-Requested-With:\n22\t - XMLHttpRequest\n23\t method: PUT\n24\t uri: http://localhost:3000/api/v1/layout/notificationChannels\n25\t response:\n26\t body:\n27\t string: ''\n28\t headers:\n29\t DATE: &id001\n30\t - PLACEHOLDER\n31\t Expires:\n32\t - '0'\n33\t Pragma:\n34\t - no-cache\n35\t X-Content-Type-Options:\n36\t - nosniff\n37\t X-GDC-TRACE-ID: *id001\n38\t status:\n39\t code: 204\n40\t message: No Content\n41\t - request:\n42\t body: null\n43\t headers:\n44\t Accept:\n45\t - application/json\n46\t Accept-Encoding:\n47\t - br, gzip, deflate\n48\t X-GDC-VALIDATE-RELATIONS:\n49\t - 'true'\n50\t X-Requested-With:\n51\t - XMLHttpRequest\n52\t method: GET\n53\t uri: http://localhost:3000/api/v1/layout/notificationChannels\n54\t response:\n55\t body:\n56\t string:\n57\t notificationChannels:\n58\t - allowedRecipients: CREATOR\n59\t customDashboardUrl: https://dashboard.site\n60\t dashboardLinkVisibility: INTERNAL_ONLY", "truncated": false}]} -{"ts": 1778572718.6659815, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Key insight from looking at `layout_notification_channels.yaml`:\n- Notification channels use a dedicated `/api/v1/layout/notificationChannels` endpoint (not the full org layout)\n- This is why they work without the datasource auth issue\n\nFor IP allowlist policies, there's no dedicated endpoint. The only option is `set_organization_layout`.\n\nNow let me understand the problem better. When `set_organization_layout` is called, the full org layout (including all datasources with their configurations) needs to be valid.\n\nLooking at the error:\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties... \n\nDatasource: demo-test-ds, user: , password: ...\"}\n```\n\nWhen we read the org layout via `get_organization_layout`, the response omits the datasource passwords. When we try to PUT the full layout back, the API sees a datasource with username but no password, which is an invalid auth combination.\n\nI need to figure out what the actual datasource structure looks like when returned from `get_organization_layout` so I can understand how to properly handle the credentials when updating the layout.\n\nLooking at this differently - the `set_organization_layout` endpoint is a full PUT operation, not a patch, so I need to check if there's a way to preserve existing datasource credentials or if the API allows omitting password fields entirely for datasources that already have credentials stored. I'm wondering if there's a special sentinel value or a different credential field like `token` that handles the \"keep existing\" semantic. Let me check how the `put_declarative_data_sources` method handles this same credential problem.", "truncated": false}]} -{"ts": 1778572718.7396538, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how data sources handle the credential issue:", "truncated": false}]} -{"ts": 1778572718.861483, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01G5vZZqboX8uztL3KUrXJC9", "input": "{\"pattern\": \"put_declarative_data_sources|credentials_path|_credentials\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572718.9779384, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01G5vZZqboX8uztL3KUrXJC9", "is_error": false, "content": "40:from gooddata_sdk.utils import get_ds_credentials, load_all_entities_dict, read_layout_from_file\n155: def put_declarative_data_sources(\n158: credentials_path: Path | None = None,\n167: credentials_path (Optional[Path], optional):\n178: self.test_data_sources_connection(declarative_data_sources, credentials_path, config_file)\n179: credentials = self._credentials_from_file(credentials_path) if credentials_path is not None else None\n223: def load_and_put_declarative_data_sources(\n226: credentials_path: Path | None = None,\n232: This method combines `load_declarative_data_sources` and `put_declarative_data_sources`\n238: credentials_path (Optional[Path], optional):\n249: self.put_declarative_data_sources(data_sources, credentials_path, config_file, test_data_sources)\n437: credentials_path: Path | None = None,\n442: If `credentials_path` is omitted then the connection\n451: credentials_path (Optional[Path], optional):\n465: if credentials_path is not None and config_file is not None:\n467: if credentials_path is not None:\n468: credentials = self._credentials_from_file(credentials_path)\n470: credentials = get_ds_credentials(config_file)\n646: def _credentials_from_file(credentials_path: Path) -> dict[str, Any]:\n647: data = read_layout_from_file(credentials_path)", "truncated": false}]} -{"ts": 1778572729.2555811, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So `put_declarative_data_sources` requires a `credentials_path` to properly handle datasource credentials. This is needed because when reading the layout, credentials are redacted.\n\nThe `set_organization_layout` has the same issue - when you read the full org layout, datasource credentials are redacted, and when you write it back, the API rejects if the credential combination is invalid.\n\nNow let me think about what we can do:\n\n**Approach 1: Handle datasource auth in the org layout write**\nWhen doing `put_declarative_ip_allowlist_policies`, we could clear the auth information from datasources before writing back. But this would break the datasource configurations.\n\n\nWhat if we just omit the datasources entirely from the layout when writing back? That won't work either - it would delete them from the organization.\n\n**Approach 2: Change the test to avoid the issue**\nThe test uses VCR cassettes that record real API calls on first run. The failure is happening during that live recording phase, so maybe we can restructure the test to avoid triggering the PUT failure while still getting the cassette recorded.\n\n**Approach 3: Examine the API endpoint more carefully**\nI should look more closely at `set_organization_layout` to see if there's a parameter to skip datasource credential validation, or if the issue is something else entirely about how the endpoint handles partial updates.\n\nLet me step back and examine how `get_organization_layout` actually returns datasource information and what credential format it uses - that might reveal what's going wrong when we try to write it back.", "truncated": false}]} -{"ts": 1778572729.3141518, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the DeclarativeDataSource model to understand credential handling:", "truncated": false}]} -{"ts": 1778572729.4590197, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01V9phXw5e6XuW1r9cMfE8ea", "input": "{\"pattern\": \"gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\"}", "truncated": false}]} -{"ts": 1778572729.5005705, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01V9phXw5e6XuW1r9cMfE8ea", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/model/declarative_data_source.py", "truncated": false}]} -{"ts": 1778572731.984815, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01TnJUpGMFfqMKyAzp6rwBcE", "input": "{\"pattern\": \"username|password|token|credential|auth\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} -{"ts": 1778572735.0262563, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TnJUpGMFfqMKyAzp6rwBcE", "is_error": false, "content": "95: ('authentication_type',): {\n137: ('password',): {\n146: ('token',): {\n152: ('username',): {\n185: 'authentication_type': (str, none_type,), # noqa: E501\n192: 'password': (str,), # noqa: E501\n196: 'token': (str,), # noqa: E501\n198: 'username': (str,), # noqa: E501\n212: 'authentication_type': 'authenticationType', # noqa: E501\n219: 'password': 'password', # noqa: E501\n223: 'token': 'token', # noqa: E501\n225: 'username': 'username', # noqa: E501\n276: authentication_type (str, none_type): Type of authentication used to connect to the database.. [optional] # noqa: E501\n283: password (str): Password for the data-source user, property is never returned back.. [optional] # noqa: E501\n287: token (str): Token as an alternative to username and password.. [optional] # noqa: E501\n289: username (str): User with permission connect the data source/database.. [optional] # noqa: E501\n386: authentication_type (str, none_type): Type of authentication used to connect to the database.. [optional] # noqa: E501\n393: password (str): Password for the data-source user, property is never returned back.. [optional] # noqa: E501\n397: token (str): Token as an alternative to username and password.. [optional] # noqa: E501\n399: username (str): User with permission connect the data source/database.. [optional] # noqa: E501", "truncated": false}]} -{"ts": 1778572750.1914165, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Key finding: `password (str): Password for the data-source user, property is never returned back.`\n\nSo the password is NEVER returned by the API. When you GET the org layout, datasources will have `username` set but `password` absent (because it's never returned). When you PUT the layout back with `username` but no `password`, the API rejects it.\n\nThis means the read-modify-write approach for `set_organization_layout` is fundamentally broken for organizations that have datasources with username/password authentication.\n\nNow let me look at what options we have:\n\n\n1. **Use a dedicated layout endpoint** - there isn't one for IP allowlist policies\n2. **Strip auth from datasources** - would break datasources \n3. **Set datasources to empty list** - would delete datasources\n4. **Use `token` auth approach** - not applicable\n5. **Skip credential validation somehow** - the `set_organization_layout` doesn't seem to have such an option\n6. **Change the test to use a cassette that avoids the issue** - the cassette would need to be fabricated\n\nThe instructions say \"Do NOT fabricate cassette YAML files\", but maybe I can create a valid cassette by recording an actual interaction that sidesteps this problem.\n\nLet me reconsider the `set_organization_layout` endpoint itself. What if I could pass a `DeclarativeOrganization` with an empty datasources list to avoid the auth validation issue? Though that would wipe out all datasources. Or maybe the endpoint has a parameter like `skip_credentials` or only requires datasources if you're actually modifying them\u2014in which case omitting them might preserve the existing ones. Let me check the endpoint documentation more carefully to see if datasources are truly required or if they're only needed when making changes.\n\nActually, I'm noticing that the notification channels test works fine because it uses a dedicated `/api/v1/layout/notificationChannels` endpoint rather than the full organization layout endpoint. The `get_declarative_notification_cha", "truncated": true}]} -{"ts": 1778572750.1981776, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check what other layout API methods exist:", "truncated": false}]} -{"ts": 1778572750.2792304, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Ez8BVJGnduSi3M3h1V5bcA", "input": "{\"pattern\": \"def (get|set|put)_.*layout\\\\b|def (get|set|put)_.*policies\\\\b|def.*ip_allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572750.3185189, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ez8BVJGnduSi3M3h1V5bcA", "is_error": false, "content": "2578: def get_agents_layout(\n2824: def get_custom_geo_collections_layout(\n3070: def get_data_sources_layout(\n3148: def get_export_templates_layout(\n3310: def get_identity_providers_layout(\n3472: def get_notification_channels_layout(\n3550: def get_organization_layout(\n3873: def get_user_groups_layout(\n4034: def get_users_layout(\n4112: def get_users_user_groups_layout(\n4190: def get_workspace_data_filters_layout(\n4268: def get_workspace_layout(\n4435: def get_workspaces_layout(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5870: def set_organization_layout(\n6297: def set_workspace_data_filters_layout(\n6467: def set_workspaces_layout(", "truncated": false}]} -{"ts": 1778572786.6973083, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the available API methods, there's no dedicated endpoint for IP allowlist policies. The only option is `set_organization_layout`.\n\nNow I need to understand the actual fix needed. Let me review the error:\n\nThe `set_organization_layout` fails because:\n1. The org layout GET response returns a datasource with `username` but no `password`\n2. When this is PUT back, the API rejects it as invalid combination\n\nThe issue is that the implementation reads the full org layout (which includes datasources with redacted credentials) and then writes it back, which causes the datasource auth issue.\n\n\nI'm considering several approaches to fix this: stripping datasources entirely would delete them, setting the password to an empty string might not work, clearing the username when password is missing could corrupt data, or somehow excluding datasources from the write operation. Let me think through what's actually happening here.\n\nThe core issue is that the API returns datasources with redacted credentials on GET, and then rejects the PUT when we send them back without passwords. I'm wondering if there's a way to preserve the datasources on the server side rather than trying to send them back\u2014maybe the test environment's staging datasource with redacted credentials is the real blocker, and I need to find a different approach entirely. environment, you'd need to provide credentials when doing the full org layout PUT.\n\nBut the notification channels test works fine because it uses a DEDICATED endpoint that doesn't touch datasources.\n\nThe real question: is there ANY way to do this test in the staging environment given the constraints?\n\nLet me look at the `layout_notification_channels.yaml` cassette more carefully to understand how cassettes work. If the cassette exists, the test doesn't make real HTTP calls - it replays from the cassette. \n\nThe test has `@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))`. If this cassette existed with valid responses,", "truncated": true}]} -{"ts": 1778572786.7196512, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the `DeclarativeOrganization` model more carefully:", "truncated": false}]} -{"ts": 1778572786.9827282, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_017HrHqD55dtG82kQAFUJkrw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 80, \"limit\": 120}", "truncated": false}]} -{"ts": 1778572787.0186925, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017HrHqD55dtG82kQAFUJkrw", "is_error": false, "content": "80\t min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,\n81\t inclusive_minimum, and regex.\n82\t additional_properties_type (tuple): A tuple of classes accepted\n83\t as additional properties values.\n84\t \"\"\"\n85\t\n86\t allowed_values = {\n87\t }\n88\t\n89\t validations = {\n90\t }\n91\t\n92\t @cached_property\n93\t def additional_properties_type():\n94\t \"\"\"\n95\t This must be a method because a model may have properties that are\n96\t of type self, this must run after the class is loaded\n97\t \"\"\"\n98\t lazy_import()\n99\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n100\t\n101\t _nullable = False\n102\t\n103\t @cached_property\n104\t def openapi_types():\n105\t \"\"\"\n106\t This must be a method because a model may have properties that are\n107\t of type self, this must run after the class is loaded\n108\t\n109\t Returns\n110\t openapi_types (dict): The key is attribute name\n111\t and the value is attribute type.\n112\t \"\"\"\n113\t lazy_import()\n114\t return {\n115\t 'organization': (DeclarativeOrganizationInfo,), # noqa: E501\n116\t 'agents': ([DeclarativeAgent],), # noqa: E501\n117\t 'custom_geo_collections': ([DeclarativeCustomGeoCollection],), # noqa: E501\n118\t 'data_sources': ([DeclarativeDataSource],), # noqa: E501\n119\t 'export_templates': ([DeclarativeExportTemplate],), # noqa: E501\n120\t 'identity_providers': ([DeclarativeIdentityProvider],), # noqa: E501\n121\t 'ip_allowlist_policies': ([DeclarativeIpAllowlistPolicy],), # noqa: E501\n122\t 'jwks': ([DeclarativeJwk],), # noqa: E501\n123\t 'notification_channels': ([DeclarativeNotificationChannel],), # noqa: E501\n124\t 'user_groups': ([DeclarativeUserGroup],), # noqa: E501\n125\t 'users': ([DeclarativeUser],), # noqa: E501\n12", "truncated": true}]} -{"ts": 1778572844.980338, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see that `data_sources` is optional (not required) in `DeclarativeOrganization`. The only required field is `organization`. \n\nNow the question is: if we do `get_organization_layout()` and get back an org layout object with `data_sources` containing datasources with redacted credentials, can we set `org_layout.data_sources = ???` to avoid the auth issue?\n\nLooking at how the API model works with `_check_return_type=False` - the model is returned as a ModelNormal instance where attributes are stored. If we could delete the `data_sources` attribute from the returned object (or set it in a way that it won't be included in the serialized body), that might avoid the issue.\n\n\nBut removing `data_sources` from the PUT body raises a bigger question: would the API preserve existing data sources or wipe them out? Since this is a full PUT operation, the behavior is unclear. Searching through the codebase, I notice that `set_organization_layout` is only used in one place\u2014the IP allowlist policies implementation\u2014which means there's no established pattern for how to handle read-modify-write operations on the full org layout.\n\nThe prior agent introduced a novel approach that's never been tested with actual datasource credentials. I'm weighing three options: fix the test to avoid non-existent users, modify the implementation to preserve datasource credentials during the PUT, or completely rethink the approach. For the second option, I'm wondering if omitting the `data_sources` field entirely would let the API keep existing datasources intact, since the model likely has all fields as optional.\n\nActually, the API uses a declarative PUT pattern\u2014what you send is what you get\u2014so omitting `data_sources` would probably delete them all. But I'm realizing the `_check_return_type=False` flag might be key here. When the model is returned without type checking, setting attributes like `ip_allowlist_policies` on that object and then serializing it back should include all those attributes in the ", "truncated": true}]} -{"ts": 1778572844.9868765, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at an existing organization layout cassette to understand the structure:", "truncated": false}]} -{"ts": 1778572845.0421576, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_016mcHaHP7qcZ26gcNg1QLDq", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/organization.yaml\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} -{"ts": 1778572845.0793655, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016mcHaHP7qcZ26gcNg1QLDq", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\tinteractions:\n3\t - request:\n4\t body: null\n5\t headers:\n6\t Accept-Encoding:\n7\t - br, gzip, deflate\n8\t X-GDC-VALIDATE-RELATIONS:\n9\t - 'true'\n10\t X-Requested-With:\n11\t - XMLHttpRequest\n12\t method: GET\n13\t uri: http://localhost:3000/api/v1/entities/organization\n14\t response:\n15\t body:\n16\t string: ''\n17\t headers:\n18\t Content-Type:\n19\t - application/vnd.gooddata.api+json\n20\t DATE: &id001\n21\t - PLACEHOLDER\n22\t Expires:\n23\t - '0'\n24\t Location:\n25\t - /api/v1/entities/admin/organizations/default\n26\t Pragma:\n27\t - no-cache\n28\t X-Content-Type-Options:\n29\t - nosniff\n30\t X-GDC-TRACE-ID: *id001\n31\t status:\n32\t code: 302\n33\t message: Found\n34\t - request:\n35\t body: null\n36\t headers:\n37\t Accept-Encoding:\n38\t - br, gzip, deflate\n39\t X-GDC-VALIDATE-RELATIONS:\n40\t - 'true'\n41\t X-Requested-With:\n42\t - XMLHttpRequest\n43\t method: GET\n44\t uri: http://localhost:3000/api/v1/entities/admin/organizations/default\n45\t response:\n46\t body:\n47\t string:\n48\t data:\n49\t attributes:\n50\t allowedOrigins: []", "truncated": false}]} -{"ts": 1778572872.1974902, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK, this is the entities API, not the layout API. Let me look at if there are any cassettes that use `get_organization_layout` or `set_organization_layout` to understand the format.\n\nActually wait, I realize from all the existing cassettes that none of them use `set_organization_layout`. This is a new operation being introduced by the IP allowlist policy feature.\n\nLet me now think about what the ACTUAL minimal fix should be.\n\nGiven the constraints:\n1. No dedicated endpoint for IP allowlist policies\n2. `set_organization_layout` fails when org has datasources with username but redacted password\n3. The test cassette doesn't exist yet and needs to be recorded\n\n\n4. Can't fabricate cassettes\n\nThe only fix that would make the test pass in a live environment is to either fix the implementation to not use `set_organization_layout` (but there's no other option) or make `put_declarative_ip_allowlist_policies` handle the datasource credential issue. One approach could be stripping the `data_sources` from the org layout before the PUT, though that would delete datasources. Alternatively, I could examine what happens when the org layout GET response uses `_check_return_type=False` and see if the datasource objects have specific properties I can detect and handle.\n\nWhen the model is returned without validation, the datasource object would have `username` set but `password` missing since the API never returns it. I could try detecting this and clearing the username, but that corrupts the data. Or I could change the `authentication_type` to something that doesn't require a password, though I'm not sure what valid values exist without access to the API documentation. Let me step back and look at the actual error message to find a different angle.\n\nThe error lists the only valid auth combinations: `none`, `user + password`, `token`, `key-pair`, or `clientId + clientSecret`. When the org layout is read, a datasource with username/password auth ends up with `username` set but `password`", "truncated": true}]} -{"ts": 1778572872.2001908, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the VCR configuration for the tests:", "truncated": false}]} -{"ts": 1778572872.2850714, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DFdYTmi2h1SR1NQ9j6tK1E", "input": "{\"pattern\": \"get_vcr|record_mode|vcr|cassette\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\", \"glob\": \"vcrpy_utils.py\"}", "truncated": false}]} -{"ts": 1778572872.3260367, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DFdYTmi2h1SR1NQ9j6tK1E", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778572874.493352, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LS9sja4Fmt5vNMBs25Ecuy", "input": "{\"pattern\": \"**/*vcrpy*\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} -{"ts": 1778572874.5524855, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LS9sja4Fmt5vNMBs25Ecuy", "is_error": false, "content": "packages/tests-support/src/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/__pycache__/vcrpy_utils.cpython-312.pyc", "truncated": false}]} -{"ts": 1778572876.1760314, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01LWCpAa914dx2CiMtbtGtyL", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\"}", "truncated": false}]} -{"ts": 1778572876.2793794, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LWCpAa914dx2CiMtbtGtyL", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} -{"ts": 1778572923.5691607, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the VCR setup:\n```python\nrecord_mode=RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE,\n```\n\nWith `RecordMode.ONCE`: if the cassette file exists, it will replay from it. If it doesn't exist, it will record new cassettes.\n\nSince the cassette `layout_ip_allowlist_policies.yaml` doesn't exist, the test is running in record mode, making real API calls to the staging server. The API calls are failing because:\n1. `employee123` user doesn't exist in the staging environment\n\n\n2. The `set_organization_layout` call fails when trying to update with redacted datasource credentials\n\nThe recording can't succeed until both issues are resolved. The core problem is that `put_declarative_ip_allowlist_policies` uses `set_organization_layout` to update just the IP allowlist policies, but it needs the full organization layout. When the GET returns the layout with redacted datasource credentials, the PUT rejects those redacted values.\n\nLooking at the error more carefully, the failure happens in the finally block where we're trying to restore the original policies. The initial PUT fails because `employee123` doesn't exist in the staging environment, and then the restore attempt fails because of the datasource credential issue. I need to either remove the non-existent user from the test data or find a valid user ID that exists in staging, but we don't have visibility into what users are available there.\n\nFor the datasource auth problem, I'm wondering if there's a way to exclude datasources from the request entirely\u2014maybe the API preserves existing datasources when they're not included in the payload. But that's speculative. Let me look at how other similar tests handle this, like the notification channels test, which uses a dedicated endpoint that only deals with notification channels rather than the entire organization layout.\n\nThe real issue is that there's no dedicated endpoint for IP allowlist policies, so we're forced to use `set_organization_layout`. But tha", "truncated": true}]} -{"ts": 1778572923.5706112, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the notification channels test for comparison:", "truncated": false}]} -{"ts": 1778572923.5874326, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_015tsNXag2jrgC1q9AhrRPXE", "input": "{\"pattern\": \"test.*notification_channel|layout_notification_channel\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778572923.6184525, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015tsNXag2jrgC1q9AhrRPXE", "is_error": false, "content": "316:@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_notification_channels.yaml\"))\n317:def test_layout_notification_channels(test_config, snapshot_notification_channels):", "truncated": false}]} -{"ts": 1778572925.6630418, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Gu47JLD94ijuKThj9ZX2d5", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 316, \"limit\": 60}", "truncated": false}]} -{"ts": 1778572925.7660956, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Gu47JLD94ijuKThj9ZX2d5", "is_error": false, "content": "316\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_notification_channels.yaml\"))\n317\tdef test_layout_notification_channels(test_config, snapshot_notification_channels):\n318\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n319\t\n320\t notification_channels_e = [\n321\t CatalogDeclarativeNotificationChannel(\n322\t id=\"webhook\",\n323\t name=\"Webhook\",\n324\t destination=CatalogWebhook(url=\"https://webhook.site\", token=\"123\"),\n325\t custom_dashboard_url=\"https://dashboard.site\",\n326\t allowed_recipients=\"CREATOR\",\n327\t ),\n328\t ]\n329\t sdk.catalog_organization.put_declarative_notification_channels(notification_channels_e)\n330\t notification_channels_o = sdk.catalog_organization.get_declarative_notification_channels()\n331\t assert notification_channels_e[0].id == notification_channels_o[0].id\n332\t assert notification_channels_e[0].name == notification_channels_o[0].name\n333\t assert notification_channels_e[0].destination == notification_channels_o[0].destination\n334\t assert notification_channels_e[0].custom_dashboard_url == notification_channels_o[0].custom_dashboard_url\n335\t assert notification_channels_e[0].allowed_recipients == notification_channels_o[0].allowed_recipients\n336\t # snapshot_notification_channels fixture restores original state in teardown\n337\t\n338\t\n339\t#\n340\t# The following tests are commented out as they require the organization to have the FEDERATED_IDENTITY_MANAGEMENT\n341\t# entitlement enabled which cannot be done via SDK and must be done by GoodData support.\n342\t#\n343\t# @gd_vcr.use_cassette(str(_fixtures_dir / \"create_identity_provider.yaml\"))\n344\t# def test_create_identity_provider(test_config):\n345\t# sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n346\t#\n347\t# identity_provider_id = \"test_identity_provider\"\n348\t# custom_claim_mapping = {\"email\": \"email\"}\n349\t# identifiers = [\"goodt", "truncated": true}]} -{"ts": 1778572928.1773582, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see! The `test_layout_notification_channels` test uses a `snapshot_notification_channels` fixture that restores original state in teardown. It doesn't use a `try/finally` block for restoration. The fixture handles the restore.\n\nLet me look at the `snapshot_notification_channels` fixture to understand how it works:", "truncated": false}]} -{"ts": 1778572928.5660772, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest for the organization tests:", "truncated": false}]} -{"ts": 1778572928.75303, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01UEsmsNsCX2wvbpXsMRy89X", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/conftest.py\"}", "truncated": false}]} -{"ts": 1778572928.7854345, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UEsmsNsCX2wvbpXsMRy89X", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\t\"\"\"\n3\tShared test fixtures for catalog tests.\n4\t\n5\tProvides:\n6\t- safe_delete: cleanup utility that swallows exceptions\n7\t- sdk: session-scoped GoodDataSdk instance\n8\t- Snapshot/restore fixtures for staging-safe testing\n9\t\"\"\"\n10\t\n11\tfrom __future__ import annotations\n12\t\n13\timport copy\n14\timport logging\n15\tfrom pathlib import Path\n16\tfrom typing import Any, Callable\n17\t\n18\timport pytest\n19\tfrom gooddata_sdk import CatalogDeclarativeDataSources, GoodDataSdk\n20\tfrom tests_support.file_utils import load_json\n21\t\n22\tlogger = logging.getLogger(__name__)\n23\t\n24\t_current_dir = Path(__file__).parent.absolute()\n25\t_credentials_path = _current_dir / \"load\" / \"data_source_credentials\" / \"data_sources_credentials.yaml\"\n26\t\n27\t\n28\tdef _capture_workspace_permissions(sdk: GoodDataSdk, workspaces: list) -> dict:\n29\t \"\"\"Capture permissions for all workspaces, skipping failures.\"\"\"\n30\t ws_permissions: dict = {}\n31\t for ws in workspaces:\n32\t try:\n33\t ws_permissions[ws.id] = sdk.catalog_permission.get_declarative_permissions(ws.id)\n34\t except Exception as e: # noqa: PERF203\n35\t logger.warning(f\"Could not capture permissions for workspace {ws.id}: {e}\")\n36\t return ws_permissions\n37\t\n38\t\n39\tdef _restore_workspace_permissions(sdk: GoodDataSdk, ws_permissions: dict) -> None:\n40\t \"\"\"Restore permissions for all workspaces, logging failures.\"\"\"\n41\t for ws_id, perms in ws_permissions.items():\n42\t try:\n43\t sdk.catalog_permission.put_declarative_permissions(ws_id, perms)\n44\t except Exception as e: # noqa: PERF203\n45\t logger.warning(f\"RESTORE FAILED [permissions for {ws_id}]: {e}\")\n46\t\n47\t\n48\tdef safe_delete(func: Callable, *args: Any, **kwargs: Any) -> None:\n49\t \"\"\"Call a cleanup function, swallowing any exception so it doesn't mask test failures.\n50\t\n51\t Use this in `finally` blocks instead of bare cleanup calls.\n52\t \"\"\"\n53\t try:\n54\t func(*args, **kwa", "truncated": true}]} -{"ts": 1778572943.5736, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! The conftest has a `snapshot_notification_channels` fixture that:\n1. Gets current notification channels\n2. Yields (test runs)\n3. After the test, restores the original notification channels\n\nThe `test_layout_notification_channels` test uses this fixture instead of a manual try/finally block.\n\nThe key difference between the IP allowlist test and the notification channels test:\n\n**Notification channels**: Uses a dedicated endpoint (`get_notification_channels_layout` / `set_notification_channels`). No datasource credential issue.\n\n**IP allowlist policies**: No dedicated endpoint, must use `set_organization_layout`. \n\nThis fails when the org has datasources with redacted credentials. I need to decide between two approaches: fixing the test by removing the problematic user and switching to a proper fixture, or fixing the implementation by handling the credential issue in `set_organization_layout`. The real solution is probably in the implementation\u2014when reading the org layout to modify IP allowlist policies, I should preserve existing datasource credentials instead of letting them get redacted.\n\nThe tricky part is that the API returns `username` without `password` for security, but if I PUT back with just `username` set, it might either clear the auth or fail validation. I need to check whether omitting `username` from the PUT body preserves the existing credential, or if I need a different approach entirely.\n\nLet me look at the `DeclarativeDataSource` model to see if `username` is actually optional\u2014if it is, maybe I can omit it from the PUT request entirely and the API will leave the existing credentials untouched.", "truncated": false}]} -{"ts": 1778572943.5863879, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the optional keys in `DeclarativeDataSource`:", "truncated": false}]} -{"ts": 1778572943.62274, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018VWrweuqRJzju9YuZ6FKxe", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 155, \"limit\": 80}", "truncated": false}]} -{"ts": 1778572943.7220423, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018VWrweuqRJzju9YuZ6FKxe", "is_error": false, "content": "155\t }\n156\t\n157\t @cached_property\n158\t def additional_properties_type():\n159\t \"\"\"\n160\t This must be a method because a model may have properties that are\n161\t of type self, this must run after the class is loaded\n162\t \"\"\"\n163\t lazy_import()\n164\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n165\t\n166\t _nullable = False\n167\t\n168\t @cached_property\n169\t def openapi_types():\n170\t \"\"\"\n171\t This must be a method because a model may have properties that are\n172\t of type self, this must run after the class is loaded\n173\t\n174\t Returns\n175\t openapi_types (dict): The key is attribute name\n176\t and the value is attribute type.\n177\t \"\"\"\n178\t lazy_import()\n179\t return {\n180\t 'id': (str,), # noqa: E501\n181\t 'name': (str,), # noqa: E501\n182\t 'schema': (str,), # noqa: E501\n183\t 'type': (str,), # noqa: E501\n184\t 'alternative_data_source_id': (str, none_type,), # noqa: E501\n185\t 'authentication_type': (str, none_type,), # noqa: E501\n186\t 'cache_strategy': (str,), # noqa: E501\n187\t 'client_id': (str,), # noqa: E501\n188\t 'client_secret': (str,), # noqa: E501\n189\t 'date_time_semantics': (str, none_type,), # noqa: E501\n190\t 'decoded_parameters': ([Parameter],), # noqa: E501\n191\t 'parameters': ([Parameter],), # noqa: E501\n192\t 'password': (str,), # noqa: E501\n193\t 'permissions': ([DeclarativeDataSourcePermission],), # noqa: E501\n194\t 'private_key': (str, none_type,), # noqa: E501\n195\t 'private_key_passphrase': (str, none_type,), # noqa: E501\n196\t 'token': (str,), # noqa: E501\n197\t 'url': (str,), # noqa: E501\n198\t 'username': (str,), # noqa: E501\n199\t }\n200\t\n201\t @cached_property\n202\t ", "truncated": true}]} -{"ts": 1778572945.8482208, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DNiKcgMEeAfUBPJjQur5dG", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 234, \"limit\": 60}", "truncated": false}]} -{"ts": 1778572945.8852603, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DNiKcgMEeAfUBPJjQur5dG", "is_error": false, "content": "234\t @convert_js_args_to_python_args\n235\t def _from_openapi_data(cls, id, name, schema, type, *args, **kwargs): # noqa: E501\n236\t \"\"\"DeclarativeDataSource - a model defined in OpenAPI\n237\t\n238\t Args:\n239\t id (str): Data source ID.\n240\t name (str): Name of the data source.\n241\t schema (str): A scheme/database with the data.\n242\t type (str): Type of database.\n243\t\n244\t Keyword Args:\n245\t _check_type (bool): if True, values for parameters in openapi_types\n246\t will be type checked and a TypeError will be\n247\t raised if the wrong type is input.\n248\t Defaults to True\n249\t _path_to_item (tuple/list): This is a list of keys or values to\n250\t drill down to the model in received_data\n251\t when deserializing a response\n252\t _spec_property_naming (bool): True if the variable names in the input data\n253\t are serialized names, as specified in the OpenAPI document.\n254\t False if the variable names in the input data\n255\t are pythonic names, e.g. snake case (default)\n256\t _configuration (Configuration): the instance to use when\n257\t deserializing a file_type parameter.\n258\t If passed, type conversion is attempted\n259\t If omitted no type conversion is done.\n260\t _visited_composed_classes (tuple): This stores a tuple of\n261\t classes that we have traveled through so that\n262\t if we see that class again we will not use its\n263\t discriminator again.\n264\t When traveling through a discriminator, the\n265\t ", "truncated": true}]} -{"ts": 1778572981.8116634, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see that `username` is optional. So when the GET response returns the org layout, the datasource object has `username` set but `password` NOT set (it's never returned).\n\nThe `_check_return_type=False` flag is key here. Let me look at how the `ModelNormal` works when `_check_return_type=False`. When we do `get_organization_layout(_check_return_type=False)`, the returned object is a raw dict-like object (ModelNormal) where:\n- `username` is set (e.g., \"some_user\")\n\n\n- `password` is NOT present in the object\n\nWhen we serialize this back via `set_organization_layout`, the serializer includes `username` but not `password`. The API then sees username without password and rejects it.\n\nI could delete the `username` attribute from each datasource before the PUT, but that would strip the auth type entirely and break the datasource connection in staging. The conftest's session-level restore would only fix this if tests fail, which they currently do.\n\nLet me trace through the error flow more carefully to understand what's actually happening.\n\nLooking at the pytest output, the first error is that `employee123` doesn't exist when we try to PUT the new policies. Then in the finally block when we attempt to restore the original policies, we hit a different error about invalid datasource auth combinations.\n\nSo the sequence is: the first PUT fails because of the non-existent user, not the datasource auth issue. The datasource auth problem only surfaces when we try to restore in the cleanup. but the underlying issue is that the datasource auth validation happens regardless of what policies are being set. The real problem is that the test environment itself has auth configuration issues that prevent any PUT operation on this endpoint from succeeding, whether it's adding new policies or restoring the original state.\n\nThe minimal fix would be to strip the `data_sources` field from the org layout before sending the PUT request, but I need to figure out whether omitting the field entirely", "truncated": true}]} -{"ts": 1778572981.8296227, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the set_agents_layout endpoint to understand partial update patterns:", "truncated": false}]} -{"ts": 1778572981.8298998, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Vk35knDsajRSWKwTUsiik6", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 5020, \"limit\": 60}", "truncated": false}]} -{"ts": 1778572981.8514466, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Vk35knDsajRSWKwTUsiik6", "is_error": false, "content": "5020\t def set_agents_layout(\n5021\t self,\n5022\t declarative_agents,\n5023\t **kwargs\n5024\t ):\n5025\t \"\"\"Set all AI agent configurations # noqa: E501\n5026\t\n5027\t Sets AI agent configurations in organization. # noqa: E501\n5028\t This method makes a synchronous HTTP request by default. To make an\n5029\t asynchronous HTTP request, please pass async_req=True\n5030\t\n5031\t >>> thread = api.set_agents_layout(declarative_agents, async_req=True)\n5032\t >>> result = thread.get()\n5033\t\n5034\t Args:\n5035\t declarative_agents (DeclarativeAgents):\n5036\t\n5037\t Keyword Args:\n5038\t _return_http_data_only (bool): response data without head status\n5039\t code and headers. Default is True.\n5040\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n5041\t will be returned without reading/decoding response data.\n5042\t Default is True.\n5043\t _request_timeout (int/float/tuple): timeout setting for this request. If\n5044\t one number provided, it will be total request timeout. It can also\n5045\t be a pair (tuple) of (connection, read) timeouts.\n5046\t Default is None.\n5047\t _check_input_type (bool): specifies if type checking\n5048\t should be done one the data sent to the server.\n5049\t Default is True.\n5050\t _check_return_type (bool): specifies if type checking\n5051\t should be done one the data received from the server.\n5052\t Default is True.\n5053\t _spec_property_naming (bool): True if the variable names in the input data\n5054\t are serialized names, as specified in the OpenAPI document.\n5055\t False if the variable names in the input data\n5056\t are pythonic names, e.g. snake case (default)\n5057\t _content_type (str/None): force body co", "truncated": true}]} -{"ts": 1778572983.95781, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01HvtrpuCtcy9pYJtaE8Fpey", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 2086, \"limit\": 30}", "truncated": false}]} -{"ts": 1778572983.9970124, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HvtrpuCtcy9pYJtaE8Fpey", "is_error": false, "content": "2086\t self.set_organization_layout_endpoint = _Endpoint(\n2087\t settings={\n2088\t 'response_type': None,\n2089\t 'auth': [],\n2090\t 'endpoint_path': '/api/v1/layout/organization',\n2091\t 'operation_id': 'set_organization_layout',\n2092\t 'http_method': 'PUT',\n2093\t 'servers': None,\n2094\t },\n2095\t params_map={\n2096\t 'all': [\n2097\t 'declarative_organization',\n2098\t ],\n2099\t 'required': [\n2100\t 'declarative_organization',\n2101\t ],\n2102\t 'nullable': [\n2103\t ],\n2104\t 'enum': [\n2105\t ],\n2106\t 'validation': [\n2107\t ]\n2108\t },\n2109\t root_map={\n2110\t 'validations': {\n2111\t },\n2112\t 'allowed_values': {\n2113\t },\n2114\t 'openapi_types': {\n2115\t 'declarative_organization':", "truncated": false}]} -{"ts": 1778572993.3206413, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The `set_organization_layout` endpoint is `/api/v1/layout/organization` with HTTP method PUT. It takes a `DeclarativeOrganization` which is a required parameter. \n\nLet me now look at how the `set_organization_layout` handles missing fields in the body. When we pass a `DeclarativeOrganization` that doesn't have `data_sources` set, what happens?\n\nActually, looking at this more carefully: when we get the org_layout with `_check_return_type=False`, the returned object is a `ModelNormal` that has all the fields set based on the API response. The `data_sources` field would be set in the `_data_store` of the model.\n \nWhen I modify `org_layout.ip_allowlist_policies = [...]`, I'm updating a field on the object. If I could somehow remove `data_sources` from the `_data_store` before calling `set_organization_layout`, the serialized PUT request wouldn't include it\u2014and I'm wondering what the API does when that field is omitted from the request body.\n\nThe key issue is whether `data_sources` is truly optional in the endpoint and the API preserves existing datasources when they're not included, or if it deletes them when they're missing from the request. I need to check the actual API documentation or cassettes to understand the semantics of the `set_organization_layout` PUT operation.", "truncated": false}]} diff --git a/transcripts/fix-C009-attempt2.jsonl b/transcripts/fix-C009-attempt2.jsonl deleted file mode 100644 index 959e8a74e..000000000 --- a/transcripts/fix-C009-attempt2.jsonl +++ /dev/null @@ -1,144 +0,0 @@ -{"ts": 1778573002.6004434, "type": "system"} -{"ts": 1778573009.7817116, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me analyze the failing test and understand what's going wrong. The error message is:\n\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n```\n\nThe error is about \"Invalid combination of auth properties\" for a datasource \"demo-test-ds\". \n\nThe problem is occurring in `put_declarative_ip_allowlist_policies` when it calls `set_organization_layout` - the read-modify-write pattern is causing issues because when the full org layout gets read back and written, it's attempting to PUT the datasource with incomplete auth credentials. There's also an earlier error about missing 'users' entities that don't exist in the system, so I need to look at the test to understand what's actually being set up and what's failing.", "truncated": false}]} -{"ts": 1778573009.7887871, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01MfLEAbbFzMcBQDtZmcebJt", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 570, \"limit\": 80}", "truncated": false}]} -{"ts": 1778573009.8037243, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MfLEAbbFzMcBQDtZmcebJt", "is_error": false, "content": "570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"group.admins\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"employee123\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"group.admins\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"employee123\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} -{"ts": 1778573009.8042865, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_013ujfxuSCcMVHqYNdyzqfr3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 50}", "truncated": false}]} -{"ts": 1778573009.825166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_013ujfxuSCcMVHqYNdyzqfr3", "is_error": false, "content": "750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} -{"ts": 1778573018.1809082, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The error is:\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n```\n\nThe problem is clear now: when reading the org layout and writing it back, the org layout contains datasources (like \"demo-test-ds\") that have auth credentials that are not fully present in the GET response (passwords are typically masked/omitted). \n\nWhen the full layout is PUT back, the server rejects it because the auth credentials are incomplete. This is a known issue with read-modify-write approaches on layouts containing sensitive data\u2014the GET response masks passwords, so when I PUT it back, the server sees an invalid combination of auth properties.\n\nI need to explore whether there's a dedicated endpoint for updating just the IP allowlist policies, or if I should handle the read-modify-write differently to preserve the original auth configuration without modifying it.", "truncated": false}]} -{"ts": 1778573018.2852287, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Ds7ARTM2d17ctngauHF74k", "input": "{\"pattern\": \"ip_allowlist\\\\|ipAllowlist\\\\|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} -{"ts": 1778573018.667458, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Ds7ARTM2d17ctngauHF74k", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778573018.763352, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_018NrTrPzyxbw7AFkBC9LpcN", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py\"}", "truncated": false}]} -{"ts": 1778573018.8059125, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018NrTrPzyxbw7AFkBC9LpcN", "is_error": false, "content": "1\t# (C) 2025 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\t\n6\tfrom attrs import define, field\n7\tfrom gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n8\t\n9\tfrom gooddata_sdk.catalog.base import Base\n10\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n11\t\n12\t\n13\t@define(kw_only=True)\n14\tclass CatalogDeclarativeIpAllowlistPolicy(Base):\n15\t id: str\n16\t allowed_sources: list[str] = field(factory=list)\n17\t user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list)\n18\t users: list[CatalogUserIdentifier] = field(factory=list)\n19\t\n20\t @staticmethod\n21\t def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]:\n22\t return DeclarativeIpAllowlistPolicy\n23\t", "truncated": false}]} -{"ts": 1778573021.950166, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the `ip_allowlist` endpoint doesn't exist in the layout_api at all. The error is because of the read-modify-write approach: when the full org layout is read and PUT back, datasources with incomplete auth credentials (password was masked in the GET response) fail.\n\nLet me look at how the other layout methods handle this, and see if there's a dedicated endpoint in the layout_api we can use.", "truncated": false}]} -{"ts": 1778573022.344003, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_0121fLDBNLgsyYTuPgGcftbK", "input": "{\"command\": \"grep -n \\\"ip_allowlist\\\\|IpAllowlist\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py | head -40\"}", "truncated": false}]} -{"ts": 1778573022.7280967, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0121fLDBNLgsyYTuPgGcftbK", "is_error": true, "content": "Blocked: grep -n \"ip_allowlist\\|IpAllowlist\" /home/runner/_work/gdc-nas/gdc-nas/sdk/goodd", "truncated": false}]} -{"ts": 1778573022.9883952, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_017swQLmfmA1qH6BEpHyGC4Y", "input": "{\"command\": \"grep -n \\\"def get_\\\\|def set_\\\\|def put_\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py | head -60\"}", "truncated": false}]} -{"ts": 1778573023.0247822, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017swQLmfmA1qH6BEpHyGC4Y", "is_error": true, "content": "Blocked: grep -n \"def get_\\|def set_\\|def put_\" /home/runner/_work/gdc-nas/gdc-nas/sdk/go", "truncated": false}]} -{"ts": 1778573025.3225725, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01QDBkX5LqxqVUNJ8BpkNmQ2", "input": "{\"pattern\": \"ip_allowlist|IpAllowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} -{"ts": 1778573025.714029, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QDBkX5LqxqVUNJ8BpkNmQ2", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778573026.0078123, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01SHZ7ff5io71ZKh5sc9qVpY", "input": "{\"pattern\": \"def (get|set|put)_\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 80}", "truncated": false}]} -{"ts": 1778573026.0414166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01SHZ7ff5io71ZKh5sc9qVpY", "is_error": false, "content": "2578: def get_agents_layout(\n2656: def get_analytics_model(\n2740: def get_automations(\n2824: def get_custom_geo_collections_layout(\n2902: def get_data_source_permissions(\n2985: def get_data_source_statistics(\n3070: def get_data_sources_layout(\n3148: def get_export_templates_layout(\n3226: def get_filter_views(\n3310: def get_identity_providers_layout(\n3388: def get_logical_model(\n3472: def get_notification_channels_layout(\n3550: def get_organization_layout(\n3629: def get_organization_permissions(\n3707: def get_user_data_filters(\n3790: def get_user_group_permissions(\n3873: def get_user_groups_layout(\n3951: def get_user_permissions(\n4034: def get_users_layout(\n4112: def get_users_user_groups_layout(\n4190: def get_workspace_data_filters_layout(\n4268: def get_workspace_layout(\n4352: def get_workspace_permissions(\n4435: def get_workspaces_layout(\n4514: def put_data_source_statistics(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5103: def set_analytics_model(\n5190: def set_automations(\n5277: def set_custom_geo_collections(\n5360: def set_data_source_permissions(\n5447: def set_export_templates(\n5530: def set_filter_views(\n5617: def set_identity_providers(\n5700: def set_logical_model(\n5787: def set_notification_channels(\n5870: def set_organization_layout(\n5953: def set_organization_permissions(\n6036: def set_user_data_filters(\n6123: def set_user_group_permissions(\n6210: def set_user_permissions(\n6297: def set_workspace_data_filters_layout(\n6380: def set_workspace_permissions(\n6467: def set_workspaces_layout(", "truncated": false}]} -{"ts": 1778573035.8089197, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no dedicated `get_ip_allowlist` or `set_ip_allowlist` method. The only way to manage IP allowlist policies is through the full organization layout (get/set_organization_layout).\n\nThe error message is:\n```\n{\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"3f9086506f424daedafb5dc8f30e026e\"}\n\n\n```\n\nThe issue is that when I fetch the organization layout via GET, sensitive credentials like datasource passwords are masked or stripped from the response. When I PUT that incomplete layout back, the server rejects it because it sees `user: yes, password: no` which is an invalid auth combination. This read-modify-write pattern doesn't work for `set_organization_layout` because the GET response is already redacted. I need to look at how other tests handle organization layout operations to find a workaround.\n\n```", "truncated": false}]} -{"ts": 1778573036.0690591, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Vww37Xwt3GjoCUWxgnxxsv", "input": "{\"pattern\": \"set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778573036.0799193, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Vww37Xwt3GjoCUWxgnxxsv", "is_error": false, "content": "777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} -{"ts": 1778573036.1039321, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01E8At1vhYvKtHrkwwNnwPUi", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778573036.1452413, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01E8At1vhYvKtHrkwwNnwPUi", "is_error": false, "content": "756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} -{"ts": 1778573038.750805, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The key issue is: when reading the org layout with GET, datasource passwords are masked. When PUT-ting back, the server rejects it because the datasource has a user but no password.\n\nLet me look at the full `put_declarative_organization_layout` method and see how it handles this:", "truncated": false}]} -{"ts": 1778573039.527552, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HZa9BuT5WSL9y7JN6n9QqQ", "input": "{\"pattern\": \"put_declarative_organization|get_declarative_organization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778573039.910496, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HZa9BuT5WSL9y7JN6n9QqQ", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778573040.2416205, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_0114KpWHD9cSL8P6RMfJbApU", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} -{"ts": 1778573040.277885, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0114KpWHD9cSL8P6RMfJbApU", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport functools\n5\tfrom typing import Any, Literal\n6\t\n7\tfrom gooddata_api_client.exceptions import NotFoundException\n8\tfrom gooddata_api_client.model.declarative_export_templates import DeclarativeExportTemplates\n9\tfrom gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n10\tfrom gooddata_api_client.model.json_api_csp_directive_in_document import JsonApiCspDirectiveInDocument\n11\tfrom gooddata_api_client.model.json_api_export_template_in_document import JsonApiExportTemplateInDocument\n12\tfrom gooddata_api_client.model.json_api_export_template_post_optional_id_document import (\n13\t JsonApiExportTemplatePostOptionalIdDocument,\n14\t)\n15\tfrom gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument\n16\tfrom gooddata_api_client.model.json_api_organization_patch import JsonApiOrganizationPatch\n17\tfrom gooddata_api_client.model.json_api_organization_patch_document import JsonApiOrganizationPatchDocument\n18\tfrom gooddata_api_client.model.json_api_organization_setting_in_document import JsonApiOrganizationSettingInDocument\n19\tfrom gooddata_api_client.model.switch_identity_provider_request import SwitchIdentityProviderRequest\n20\t\n21\tfrom gooddata_sdk import CatalogDeclarativeExportTemplate, CatalogExportTemplate\n22\tfrom gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase\n23\tfrom gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective\n24\tfrom gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider\n25\tfrom gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument\n26\tfrom gooddata_sdk.catalog.organization.entity_model.llm_provider import (\n27\t CatalogLlmProvider,\n28\t CatalogLlmProviderDocument,\n29\t CatalogLlmProviderPatch,\n30\t CatalogLlmProviderPatchDocument,\n31\t)\n32\tfrom gooddata_sdk.c", "truncated": true}]} -{"ts": 1778573042.9638257, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Rk2jXe2PtbxBNkdAAapfgb", "input": "{\"pattern\": \"set_notification_channels|notification_channel|set_identity_providers\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} -{"ts": 1778573042.9979026, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Rk2jXe2PtbxBNkdAAapfgb", "is_error": false, "content": "9:from gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n35:from gooddata_sdk.catalog.organization.layout.notification_channel import CatalogDeclarativeNotificationChannel\n634: def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:\n644: for nc in self._layout_api.get_notification_channels_layout().notification_channels\n647: def put_declarative_notification_channels(\n648: self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n654: notification_channels (list[CatalogDeclarativeNotificationChannel]):\n660: api_ncs = [nc.to_api() for nc in notification_channels]\n661: self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n687: self._layout_api.set_identity_providers(declarative_identity_provider=api_idps)", "truncated": false}]} -{"ts": 1778573047.4959223, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! For notification channels, they use `get_notification_channels_layout()` and `set_notification_channels()` - there are dedicated endpoints for these. Similarly for identity providers.\n\nBut the IP allowlist policies don't have dedicated endpoints - they only appear in the full org layout.\n\nHowever, the error shows that when we PUT back the full org layout, the server rejects it because of datasource authentication issues. The datasources have their passwords masked in the GET response, so when we PUT back, it fails validation.\n\nLet me look at how the full organization layout get/put is done in the existing tests to understand how others handle this.", "truncated": false}]} -{"ts": 1778573048.3063338, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0116G7Xr4zQggtTFJB9qNxTJ", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} -{"ts": 1778573048.7013912, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0116G7Xr4zQggtTFJB9qNxTJ", "is_error": false, "content": "No matches found", "truncated": false}]} -{"ts": 1778573048.7433405, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Dk3xeZz9yxqjguNV72joe9", "input": "{\"pattern\": \"get_organization_layout|set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778573048.7775166, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Dk3xeZz9yxqjguNV72joe9", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} -{"ts": 1778573053.7536654, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So `set_organization_layout` is only used in the new IP allowlist policy code. No other method uses it directly. \n\nThe error is that when reading the full org layout and writing it back, the datasource password is masked (not returned), so the PUT fails because the datasource has a user but no password.\n\nLet me check what the DeclarativeOrganization model looks like and if there's a way to avoid sending data sources in the PUT.\n\nActually, looking at this more carefully - I need to understand what's happening. The full organization layout includes data sources with masked passwords. When we PUT it back, the server rejects it.\n \nNow I'm examining the DeclarativeOrganization schema to see what fields are available.", "truncated": false}]} -{"ts": 1778573053.7607636, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_016Mxx1rwS8arUEYn2zq7EuT", "input": "{\"pattern\": \"**/declarative_organization.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client\"}", "truncated": false}]} -{"ts": 1778573053.7900732, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016Mxx1rwS8arUEYn2zq7EuT", "is_error": false, "content": "gooddata-api-client/build/lib/gooddata_api_client/model/declarative_organization.py\ngooddata-api-client/gooddata_api_client/model/declarative_organization.py", "truncated": false}]} -{"ts": 1778573055.8554795, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Y7LKeNsUNx2GS2h3t592SH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"limit\": 80}", "truncated": false}]} -{"ts": 1778573055.8892395, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Y7LKeNsUNx2GS2h3t592SH", "is_error": false, "content": "1\t\"\"\"\n2\t OpenAPI definition\n3\t\n4\t No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501\n5\t\n6\t The version of the OpenAPI document: v0\n7\t Contact: support@gooddata.com\n8\t Generated by: https://openapi-generator.tech\n9\t\"\"\"\n10\t\n11\t\n12\timport re # noqa: F401\n13\timport sys # noqa: F401\n14\t\n15\tfrom gooddata_api_client.model_utils import ( # noqa: F401\n16\t ApiTypeError,\n17\t ModelComposed,\n18\t ModelNormal,\n19\t ModelSimple,\n20\t cached_property,\n21\t change_keys_js_to_python,\n22\t convert_js_args_to_python_args,\n23\t date,\n24\t datetime,\n25\t file_type,\n26\t none_type,\n27\t validate_get_composed_info,\n28\t OpenApiModel\n29\t)\n30\tfrom gooddata_api_client.exceptions import ApiAttributeError\n31\t\n32\t\n33\tdef lazy_import():\n34\t from gooddata_api_client.model.declarative_agent import DeclarativeAgent\n35\t from gooddata_api_client.model.declarative_custom_geo_collection import DeclarativeCustomGeoCollection\n36\t from gooddata_api_client.model.declarative_data_source import DeclarativeDataSource\n37\t from gooddata_api_client.model.declarative_export_template import DeclarativeExportTemplate\n38\t from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider\n39\t from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n40\t from gooddata_api_client.model.declarative_jwk import DeclarativeJwk\n41\t from gooddata_api_client.model.declarative_notification_channel import DeclarativeNotificationChannel\n42\t from gooddata_api_client.model.declarative_organization_info import DeclarativeOrganizationInfo\n43\t from gooddata_api_client.model.declarative_user import DeclarativeUser\n44\t from gooddata_api_client.model.declarative_user_group import DeclarativeUserGroup\n45\t from gooddata_api_client.model.declarative_workspace import DeclarativeWorkspace\n46\t from gooddata_api_client.mode", "truncated": true}]} -{"ts": 1778573057.8807747, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01S3ZEduRGisoB9SeUKrTadH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"offset\": 80, \"limit\": 120}", "truncated": false}]} -{"ts": 1778573057.9238005, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01S3ZEduRGisoB9SeUKrTadH", "is_error": false, "content": "80\t min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,\n81\t inclusive_minimum, and regex.\n82\t additional_properties_type (tuple): A tuple of classes accepted\n83\t as additional properties values.\n84\t \"\"\"\n85\t\n86\t allowed_values = {\n87\t }\n88\t\n89\t validations = {\n90\t }\n91\t\n92\t @cached_property\n93\t def additional_properties_type():\n94\t \"\"\"\n95\t This must be a method because a model may have properties that are\n96\t of type self, this must run after the class is loaded\n97\t \"\"\"\n98\t lazy_import()\n99\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n100\t\n101\t _nullable = False\n102\t\n103\t @cached_property\n104\t def openapi_types():\n105\t \"\"\"\n106\t This must be a method because a model may have properties that are\n107\t of type self, this must run after the class is loaded\n108\t\n109\t Returns\n110\t openapi_types (dict): The key is attribute name\n111\t and the value is attribute type.\n112\t \"\"\"\n113\t lazy_import()\n114\t return {\n115\t 'organization': (DeclarativeOrganizationInfo,), # noqa: E501\n116\t 'agents': ([DeclarativeAgent],), # noqa: E501\n117\t 'custom_geo_collections': ([DeclarativeCustomGeoCollection],), # noqa: E501\n118\t 'data_sources': ([DeclarativeDataSource],), # noqa: E501\n119\t 'export_templates': ([DeclarativeExportTemplate],), # noqa: E501\n120\t 'identity_providers': ([DeclarativeIdentityProvider],), # noqa: E501\n121\t 'ip_allowlist_policies': ([DeclarativeIpAllowlistPolicy],), # noqa: E501\n122\t 'jwks': ([DeclarativeJwk],), # noqa: E501\n123\t 'notification_channels': ([DeclarativeNotificationChannel],), # noqa: E501\n124\t 'user_groups': ([DeclarativeUserGroup],), # noqa: E501\n125\t 'users': ([DeclarativeUser],), # noqa: E501\n12", "truncated": true}]} -{"ts": 1778573073.5983717, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the full picture. The `DeclarativeOrganization` schema includes `data_sources` which have auth properties. When we GET the organization layout, the passwords are masked/null. When we PUT it back, the server rejects it because of the incomplete datasource credentials.\n\nThe fundamental issue is that the read-modify-write approach for the full org layout is broken because:\n1. GET returns org layout with masked datasource passwords\n2. PUT with the masked passwords fails validation\n\nThe real question is: how can we update just the `ip_allowlist_policies` field without breaking the datasource auth?\n\nLooking at the approach, there are a few options:\n\n\n1. Remove the `data_sources` field from the org layout before PUTting back \n2. Find another way to only update the ip_allowlist_policies\n\nLet me check whether `set_organization_layout` actually validates datasource auth properties. Looking at the error, it's clear the server is rejecting the datasource because it has a username but no password, which violates the auth validation rules.\n\nThe real issue is that when the org layout is fetched, the password field gets masked or stripped out. When I PUT it back with just the username, the server rejects it as an invalid auth combination. I'm weighing my options: stripping the `data_sources` field entirely risks deleting them, and setting it to an empty list has the same problem. The safest approach might be to omit the `data_sources` key from the PUT request entirely, but I need to understand whether the API treats missing fields as \"don't change\" or \"delete.\"\n\nLooking at the test setup, it's using a VCR cassette called `layout_ip_allowlist_policies.yaml` to mock the API responses, so the test shouldn't be hitting a live server. Let me check if that cassette file actually exists and what it contains.", "truncated": false}]} -{"ts": 1778573073.600673, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01AmXqhpub2r5EcSnECRmdTK", "input": "{\"pattern\": \"**/layout_ip_allowlist_policies.yaml\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} -{"ts": 1778573073.6162353, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Cq1AfKfQbdozfcRigD8247", "input": "{\"pattern\": \"**/_fixtures_dir*\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog\"}", "truncated": false}]} -{"ts": 1778573073.6409242, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01AmXqhpub2r5EcSnECRmdTK", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml", "truncated": false}]} -{"ts": 1778573073.6414046, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Cq1AfKfQbdozfcRigD8247", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778573085.192074, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette exists. Let me check the cassette file to understand what's happening.\n\nWait - the test output shows that the test is actually hitting the live server and getting a real 400 error. Let me re-read the failing test output more carefully:\n\n```\nDuring handling of the above exception, another exception occurred:\ntests/catalog/test_catalog_organization.py:600: in test_layout_ip_allowlist_policies\n sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n```\n\nSo the first exception happened in the `try` block (but we don't see it in the output). \n\nThe second exception happens in the `finally` block when trying to restore `original_policies`. The test flow is: GET original policies succeeds, PUT new policies fails because the referenced user doesn't exist, then in the finally block the restore also fails with a datasource auth issue.\n\nLooking more carefully at the traceback, the actual failure is from the restore call itself\u2014when `put_declarative_ip_allowlist_policies` reads back the full org layout and tries to PUT it, the layout contains datasources with masked passwords that cause the auth validation to fail.\n\nThe cassette file should have the recorded responses, but I need to verify it has the right data for this scenario.", "truncated": false}]} -{"ts": 1778573085.201973, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_011A9ZdRCuyZTLpMNaA25cg2", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} -{"ts": 1778573085.2296975, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011A9ZdRCuyZTLpMNaA25cg2", "is_error": true, "content": "File content (927KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.", "truncated": false}]} -{"ts": 1778573093.9674752, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette file is 927KB! It has a full set of responses. Let me check if the test is actually using the cassette or hitting a live server. Since the cassette exists and has content, it must be a recorded cassette. But then why is it failing with a real HTTP 400 error?\n\nWait - looking at the error output again:\n```\nE HTTP response headers: Content-Length: 330\nE Expires: 0\nE X-Content-Type-Options: nosniff\n...\nE Date: Tue, 12 May 2026 08:03:18 GMT\n\n\n```\n\nThis has a real date (2026-05-12, today's date), and the response headers look real. This means the test is NOT using the cassette or the cassette doesn't have the right responses. Let me reconsider the ground rules about not fabricating cassette files since they'll be re-recorded anyway. The cassette exists at `packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml` and is 927KB, but I need to verify if it actually contains valid VCR responses for this test.\n\n```", "truncated": false}]} -{"ts": 1778573093.9778664, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DTZLDzdKQc2dYnL41C8hKw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} -{"ts": 1778573094.0081472, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DTZLDzdKQc2dYnL41C8hKw", "is_error": false, "content": "1\tinteractions:\n2\t - request:\n3\t body: null\n4\t headers:\n5\t Accept:\n6\t - application/json\n7\t Accept-Encoding:\n8\t - br, gzip, deflate\n9\t X-GDC-VALIDATE-RELATIONS:\n10\t - 'true'\n11\t X-Requested-With:\n12\t - XMLHttpRequest\n13\t method: GET\n14\t uri: http://localhost:3000/api/v1/layout/organization\n15\t response:\n16\t body:\n17\t string:\n18\t agents:\n19\t - aiKnowledge: true\n20\t availableToAll: true\n21\t enabled: true\n22\t id: default-ai-assistant\n23\t name: Default GoodData AI Assistant\n24\t skillsMode: all\n25\t customGeoCollections: []\n26\t dataSources:\n27\t - alternativeDataSourceId: ds-put-abc-id\n28\t authenticationType: USERNAME_PASSWORD\n29\t id: demo-test-ds\n30\t name: demo-test-ds\n31\t permissions:\n32\t - assignee:\n33\t id: demo2\n34\t type: user\n35\t name: MANAGE\n36\t - assignee:\n37\t id: demoGroup\n38\t type: userGroup\n39\t name: USE\n40\t schema: demo\n41\t type: POSTGRESQL\n42\t url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\n43\t username: postgres\n44\t exportTemplates: []\n45\t identityProviders:\n46\t - id: defaultIdp\n47\t idpType: DEX_IDP\n48\t ipAllowlistPolicies: []\n49\t jwks: []\n50\t notificationChannels: []", "truncated": false}]} -{"ts": 1778573097.3050752, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I can see the structure! The cassette has a GET response for the org layout. Notice it doesn't have the `password` field in the datasource. This is the masked response.\n\nNow I need to check what happens with the PUT responses. Let me look further in the cassette file to find the PUT requests.", "truncated": false}]} -{"ts": 1778573098.0720143, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01WdSsvmFVsxz9aCiKZNWern", "input": "{\"pattern\": \"method: PUT|status:|400\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} -{"ts": 1778573098.1046343, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WdSsvmFVsxz9aCiKZNWern", "is_error": false, "content": "2144: status:\n4288: status:\n6425: method: PUT\n6432: status: 400\n6446: status:\n6447: code: 400\n8590: status:\n10717: method: PUT\n10726: status: 400\n10740: status:\n10741: code: 400\n12884: status:\n15028: status:\n17165: method: PUT\n17172: status: 400\n17186: status:\n17187: code: 400\n19330: status:\n21457: method: PUT\n21466: status: 400\n21480: status:\n21481: code: 400", "truncated": false}]} -{"ts": 1778573101.485494, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There are multiple PUT requests in the cassette, and they all return status 400! This is the problem. The cassette has recorded the 400 errors. The PUTs return 400 in the cassette itself.\n\nLet me look at what the cassette PUT requests contain and what the 400 responses say.", "truncated": false}]} -{"ts": 1778573102.0067546, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01LPfSaeeqzH776wBPo8unWw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6420, \"limit\": 60}", "truncated": false}]} -{"ts": 1778573102.0504959, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LPfSaeeqzH776wBPo8unWw", "is_error": false, "content": "6420\t - application/json\n6421\t X-GDC-VALIDATE-RELATIONS:\n6422\t - 'true'\n6423\t X-Requested-With:\n6424\t - XMLHttpRequest\n6425\t method: PUT\n6426\t uri: http://localhost:3000/api/v1/layout/organization\n6427\t response:\n6428\t body:\n6429\t string:\n6430\t detail: 'Some of given referenced ''users'' entities do not exist. Not existing\n6431\t IDs: [Identifier(employee123)/Organization(default)]'\n6432\t status: 400\n6433\t title: Bad Request\n6434\t traceId: NORMALIZED_TRACE_ID_000000000000\n6435\t headers:\n6436\t Content-Type:\n6437\t - application/problem+json\n6438\t DATE: *id001\n6439\t Expires:\n6440\t - '0'\n6441\t Pragma:\n6442\t - no-cache\n6443\t X-Content-Type-Options:\n6444\t - nosniff\n6445\t X-GDC-TRACE-ID: *id001\n6446\t status:\n6447\t code: 400\n6448\t message: Bad Request\n6449\t - request:\n6450\t body: null\n6451\t headers:\n6452\t Accept:\n6453\t - application/json\n6454\t Accept-Encoding:\n6455\t - br, gzip, deflate\n6456\t X-GDC-VALIDATE-RELATIONS:\n6457\t - 'true'\n6458\t X-Requested-With:\n6459\t - XMLHttpRequest\n6460\t method: GET\n6461\t uri: http://localhost:3000/api/v1/layout/organization\n6462\t response:\n6463\t body:\n6464\t string:\n6465\t agents:\n6466\t - aiKnowledge: true\n6467\t availableToAll: true\n6468\t enabled: true\n6469\t id: default-ai-assistant\n6470\t name: Default GoodData AI Assistant\n6471\t skillsMode: all\n6472\t customGeoCollections: []\n6473\t dataSources:\n6474\t - alternativeDataSourceId: ds-put-abc-id\n6475\t authenticationType: USERNAME_PASSWORD\n6476\t id: demo-test-ds\n6477\t name: demo-test-ds\n6478\t permissions:\n6479\t - as", "truncated": true}]} -{"ts": 1778573108.6583698, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern. In the cassette:\n\n1. The first PUT (with new_policies that includes employee123 user) returns 400 with \"users entities do not exist: employee123\" - this is expected and is within the `try` block. The `put_declarative_ip_allowlist_policies` doesn't catch this, so the exception propagates out of the try block and into the finally block.\n\n2. In the finally block, it calls `put_declarative_ip_allowlist_policies(original_policies)` which:\n a. GETs the org layout \n b. PUTs the org layout back with the original empty `ip_allowlist_policies`\n \n3. But the PUT in step 2b also returns 400 in the cassette! This is strange - I need to check if the subsequent PUTs are also hitting the datasource auth error, so let me look at what's happening at line 10717 where the second PUT occurs.", "truncated": false}]} -{"ts": 1778573108.676665, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01RwKM9sFfiE1Qxt25H1gWV6", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 10710, \"limit\": 50}", "truncated": false}]} -{"ts": 1778573108.7103844, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01RwKM9sFfiE1Qxt25H1gWV6", "is_error": false, "content": "10710\t - br, gzip, deflate\n10711\t Content-Type:\n10712\t - application/json\n10713\t X-GDC-VALIDATE-RELATIONS:\n10714\t - 'true'\n10715\t X-Requested-With:\n10716\t - XMLHttpRequest\n10717\t method: PUT\n10718\t uri: http://localhost:3000/api/v1/layout/organization\n10719\t response:\n10720\t body:\n10721\t string:\n10722\t detail: 'Invalid combination of auth properties. Only none, user + password,\n10723\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n10724\t user: , password: , token: , key-pair: , clientId: ,\n10725\t clientSecret: '\n10726\t status: 400\n10727\t title: Bad Request\n10728\t traceId: NORMALIZED_TRACE_ID_000000000000\n10729\t headers:\n10730\t Content-Type:\n10731\t - application/problem+json\n10732\t DATE: *id001\n10733\t Expires:\n10734\t - '0'\n10735\t Pragma:\n10736\t - no-cache\n10737\t X-Content-Type-Options:\n10738\t - nosniff\n10739\t X-GDC-TRACE-ID: *id001\n10740\t status:\n10741\t code: 400\n10742\t message: Bad Request\n10743\t - request:\n10744\t body: null\n10745\t headers:\n10746\t Accept:\n10747\t - application/json\n10748\t Accept-Encoding:\n10749\t - br, gzip, deflate\n10750\t X-GDC-VALIDATE-RELATIONS:\n10751\t - 'true'\n10752\t X-Requested-With:\n10753\t - XMLHttpRequest\n10754\t method: GET\n10755\t uri: http://localhost:3000/api/v1/layout/organization\n10756\t response:\n10757\t body:\n10758\t string:\n10759\t agents:", "truncated": false}]} -{"ts": 1778573135.6066444, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I can clearly see the problem! The cassette records the PUT responses as 400 errors. This is because the cassette was recorded when the PUTs were actually failing (the test was failing when the cassette was created).\n\nThe fundamental issue is: when the full org layout is read and PUT back, the datasource has `username: postgres` but no password field (it's masked). The server rejects this as \"Invalid combination of auth properties\".\n\nThe fix options are:\n1. **Don't use read-modify-write for set_organization_layout** - find another endpoint or approach\n2. **Before PUT, remove the `data_sources` field or set it to not include auth info** - risky, might delete datasources\n\n\n3. **Use a different endpoint** - but there's no dedicated one for IP allowlist policies\n\nI'm realizing the cassette might have been recorded with these failures already baked in, which is odd. Let me reconsider whether this cassette was actually created fresh or if it's a stale one that wasn't properly cleaned up. The test flow depends on understanding what the cassette actually contains and whether it's meant to show success or failure.\n\nLooking at the cassette structure, I can see there are four PUT requests all returning 400 errors. The first one fails with \"users entities do not exist: employee123\" when trying to put the new policies, and the second fails with \"Invalid combination of auth properties\" when attempting to restore the original policies in the finally block. This tells me the test was already failing when the cassette was recorded.\n\nThe root issue appears to be in how `put_declarative_ip_allowlist_policies` handles the full org layout - when it reads and PUTs back the configuration, the datasource password gets stripped out, triggering that 400 error. I need to figure out how to prevent this auth stripping when restoring the policies.\n\nI'm also noticing the conftest warning about detecting test failures and restoring a session snapshot, which might be triggering additional PUT c", "truncated": true}]} -{"ts": 1778573135.6167443, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NX7Cjwdks51bb6ZcNTH6aH", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 5870, \"limit\": 100}", "truncated": false}]} -{"ts": 1778573135.6479452, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NX7Cjwdks51bb6ZcNTH6aH", "is_error": false, "content": "5870\t def set_organization_layout(\n5871\t self,\n5872\t declarative_organization,\n5873\t **kwargs\n5874\t ):\n5875\t \"\"\"Set organization layout # noqa: E501\n5876\t\n5877\t Sets complete layout of organization, like workspaces, user-groups, etc. # noqa: E501\n5878\t This method makes a synchronous HTTP request by default. To make an\n5879\t asynchronous HTTP request, please pass async_req=True\n5880\t\n5881\t >>> thread = api.set_organization_layout(declarative_organization, async_req=True)\n5882\t >>> result = thread.get()\n5883\t\n5884\t Args:\n5885\t declarative_organization (DeclarativeOrganization):\n5886\t\n5887\t Keyword Args:\n5888\t _return_http_data_only (bool): response data without head status\n5889\t code and headers. Default is True.\n5890\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n5891\t will be returned without reading/decoding response data.\n5892\t Default is True.\n5893\t _request_timeout (int/float/tuple): timeout setting for this request. If\n5894\t one number provided, it will be total request timeout. It can also\n5895\t be a pair (tuple) of (connection, read) timeouts.\n5896\t Default is None.\n5897\t _check_input_type (bool): specifies if type checking\n5898\t should be done one the data sent to the server.\n5899\t Default is True.\n5900\t _check_return_type (bool): specifies if type checking\n5901\t should be done one the data received from the server.\n5902\t Default is True.\n5903\t _spec_property_naming (bool): True if the variable names in the input data\n5904\t are serialized names, as specified in the OpenAPI document.\n5905\t False if the variable names in the input data\n5906\t are pythonic names, e.g. snake case (default)\n5", "truncated": true}]} -{"ts": 1778573286.6969438, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The API documentation says `set_organization_layout` \"Sets complete layout of organization\". This means it's a complete replacement - any field not included might be cleared/deleted.\n\nLet me look at how the cassette was structured again more carefully. The cassette has failures recorded. The test is failing because the cassette has 400 errors. \n\nThe key question is: should I:\n1. Fix the code to avoid the 400 error AND delete the cassette so it gets re-recorded\n2. Or fix the cassette manually\n\nGiven that the task description says \"Do NOT fabricate cassette YAML files \u2014 they will be re-recorded by the pipeline after you finish. \n\nOption 1 is the right approach - delete the problematic cassette and fix the code. The instruction about stale cassettes being already deleted suggests I should remove this one too since it contains baked-in failures. The pipeline has a mechanism to re-record cassettes, so deleting it and fixing the underlying code issue is the way forward.\n\nLooking at the test flow more carefully, the real problem is that steps 2 and 4 both fail when trying to PUT the org layout back - the full layout includes a datasource with a postgres username but no password, which the API rejects. I need to either fix the code to avoid the read-modify-write pattern on the full org layout or handle the datasource issue properly. because of datasource auth. That's expected. But step 4 also fails because of datasource auth. Actually step 4 is the `put_declarative_ip_allowlist_policies(original_policies)` call in the finally block.\n\nWait, looking at the flow again:\n- `put_declarative_ip_allowlist_policies(new_policies)`: GETs org layout, sets ip_allowlist_policies=new, PUTs org layout back\n - This fails with 400: users entities do not exist (employee123)\n - This is expected, it's in a try block\n- In the finally block: `put_declarative_ip_allowlist_policies(original_policies)`: GETs org layout, sets ip_allowlist_policies=original (empty []), PUTs org layout back\n - This ", "truncated": true}]} -{"ts": 1778573286.6970382, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the cassette for more context:", "truncated": false}]} -{"ts": 1778573286.6972933, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01ArxeCFzZ1cRGVhoUwP1YAY", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 50, \"limit\": 120}", "truncated": false}]} -{"ts": 1778573286.7171073, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01ArxeCFzZ1cRGVhoUwP1YAY", "is_error": false, "content": "50\t notificationChannels: []\n51\t organization:\n52\t allowedOrigins: []\n53\t colorPalettes: []\n54\t cspDirectives: []\n55\t earlyAccess: enableAlerting\n56\t earlyAccessValues:\n57\t - enableAlerting\n58\t - enableSmtp\n59\t - enablePreAggregationDatasets\n60\t - enableScheduling\n61\t - enableCompositeGrain\n62\t - enableUserManagement\n63\t - enableRawExports\n64\t - enableFlexibleDashboardLayout\n65\t hostname: localhost\n66\t id: default\n67\t identityProvider:\n68\t id: defaultIdp\n69\t type: identityProvider\n70\t name: Default Organization\n71\t permissions:\n72\t - assignee:\n73\t id: adminGroup\n74\t type: userGroup\n75\t name: MANAGE\n76\t settings: []\n77\t themes: []\n78\t userGroups:\n79\t - id: adminGroup\n80\t permissions: []\n81\t - id: adminQA1Group\n82\t parents:\n83\t - id: adminGroup\n84\t type: userGroup\n85\t permissions: []\n86\t - id: demoGroup\n87\t name: demo group\n88\t permissions: []\n89\t - id: visitorsGroup\n90\t name: visitors\n91\t parents:\n92\t - id: demoGroup\n93\t type: userGroup\n94\t permissions: []\n95\t users:\n96\t - id: admin\n97\t permissions: []\n98\t settings: []\n99\t userGroups:\n100\t - id: adminGroup\n101\t type: userGroup\n102\t - authId: NORMALIZED_AUTH_ID\n103\t email: demo@example.com\n104\t firstname: Demo\n105\t id: demo\n106\t lastname: User\n107\t permissions: []\n108\t settings: []\n109\t ", "truncated": true}]} -{"ts": 1778573328.3716877, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Looking at the cassette, the org has `id: default`, not `python-sdk-dex`. And the users in the cassette are `admin`, `demo`, `demo2`. There's no `employee123` user. So the cassette was recorded against a different environment.\n\nBut the cassette DOES have the PUT failures (400 errors). This is interesting. The cassette must have been recorded with the failing PUTs. Why?\n\nActually - wait. I just realized something. The cassette might have been created by the prior agent specifically to capture the test behavior - BUT the test was already failing when the cassette was created. So the cassette faithfully records the failure.\n \nSo the real question is whether the live server would have the same issues. The test would fail on a live staging instance because `employee123` doesn't exist and the datasource auth would block the PUT calls. If the cassette gets deleted, the test needs both of those problems fixed to pass against the actual server.\n\nLooking at the test data more carefully, I need to understand what user groups are being referenced and whether they're valid in the staging environment. I need to swap out the test data to use users and groups that actually exist in the test environment \u2014 `demo2` instead of `employee123`, and `demoGroup` instead of `group.admins`. That should let the PUT request succeed once I also fix the datasource authentication issue. The full solution involves updating the test data, handling incomplete datasource auth in the `put_declarative_ip_allowlist_policies` method, and removing the stale cassette. Now I'm trying to figure out how to address the datasource auth problem.\n\nWhen the org layout GET returns, it includes a datasource with a username but no password, and the server rejects it on PUT. I could either clear the `data_sources` field entirely before sending it back, or remove that attribute from the object so it doesn't get serialized. Let me explore how ModelNormal handles attribute deletion and whether removing the field would pre", "truncated": true}]} -{"ts": 1778573328.3805187, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the conftest and VCR setup:", "truncated": false}]} -{"ts": 1778573328.3809576, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01ChPNobiRCwF2tywXHyUAfD", "input": "{\"pattern\": \"gd_vcr|vcrpy|use_cassette|record_mode\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 40}", "truncated": false}]} -{"ts": 1778573328.6417518, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01ChPNobiRCwF2tywXHyUAfD", "is_error": false, "content": "packages/gooddata-sdk/tests/table/test_table.py:9:from tests_support.vcrpy_utils import get_vcr\npackages/gooddata-sdk/tests/table/test_table.py:11:gd_vcr = get_vcr()\npackages/gooddata-sdk/tests/table/test_table.py:28:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_just_attribute.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:38:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_just_metric.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:52:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_and_metric.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:67:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_metric_and_filter.yaml\"))\npackages/gooddata-sdk/tests/table/test_table.py:83:@gd_vcr.use_cassette(str(_fixtures_dir / \"table_with_attribute_show_all_values.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:9:from tests_support.vcrpy_utils import get_vcr\npackages/gooddata-sdk/tests/support/test_support.py:11:gd_vcr = get_vcr()\npackages/gooddata-sdk/tests/support/test_support.py:17:@gd_vcr.use_cassette(str(_fixtures_dir / \"is_available.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:28:@gd_vcr.use_cassette(str(_fixtures_dir / \"is_available_no_access.yaml\"))\npackages/gooddata-sdk/tests/support/test_support.py:35:@gd_vcr.use_cassette(str(_fixtures_dir / \"wait_till_available_no_wait.yaml\"))\npackages/gooddata-sdk/tests/overview.md:4:[vcrpy](https://pypi.org/project/vcrpy/). Furthermore, some of the unit tests use the [pytest-snapshot](https://pypi.org/project/pytest-snapshot/)\npackages/gooddata-sdk/tests/overview.md:39:## Component tests with vcrpy\npackages/gooddata-sdk/tests/overview.md:41:The vcrpy simplifies mocking HTTP endpoints. The component tests use the GoodData microservices environment\npackages/gooddata-sdk/tests/overview.md:48:Additionally, make sure that every time you use vcrpy, you configure the tool:\npackages/gooddata-sdk/tests/overview.md:62:gd_vcr = vcr.VCR(filter_headers=[\"authori", "truncated": true}]} -{"ts": 1778573328.6520123, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_015BANonUUULbobrYPaoaeY3", "input": "{\"pattern\": \"**/conftest.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\"}", "truncated": false}]} -{"ts": 1778573328.6897714, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015BANonUUULbobrYPaoaeY3", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/conftest.py\npackages/gooddata-sdk/tests/conftest.py", "truncated": false}]} -{"ts": 1778573331.1544678, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01UTe6dvrsWjXXkrLGT4rTh7", "input": "{\"pattern\": \"**/vcrpy_utils.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} -{"ts": 1778573331.187915, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UTe6dvrsWjXXkrLGT4rTh7", "is_error": false, "content": "packages/tests-support/src/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/vcrpy_utils.py", "truncated": false}]} -{"ts": 1778573337.2291749, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_019wmgccLAKuJsk6BxrUZ3Td", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\"}", "truncated": false}]} -{"ts": 1778573337.4267926, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_019wmgccLAKuJsk6BxrUZ3Td", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} -{"ts": 1778573403.8686192, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the VCR setup much better! Key insights:\n\n1. **VCR record mode**: `RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE`\n - Without `OVERWRITE` env var: `RecordMode.ONCE` - records if cassette doesn't exist, replays if it does\n - With `OVERWRITE`: re-records everything\n\n2. **Body matching**: The custom body matcher strips env-specific fields (`password`, `token`, `url`, `username`, `privateKey`, etc.) before comparing. This means the PUT body will match even if the datasource URL/username differ.\n\n\n3. **Normalization**: The VCR normalizes org IDs, hostnames, and other environment-specific values so cassettes recorded with one org can match requests from different environments.\n\nSo the body matcher is stripping those sensitive fields like `username` and `password` before comparison, which should allow the cassette's PUT interactions to match the live server's requests. But then why isn't it working?\n\nLet me check the match configuration again\u2014it's set to match on method, path, query, and body. The body matching strips environment-specific fields, so the cassette's PUT to `/api/v1/layout/organization` should match the incoming request. Looking at the cassette's response for that second PUT, I'm seeing an error about invalid auth properties\u2014the datasource has a username but no password, which violates the allowed auth combinations.\n\nThe test is getting the exact same error message back, but the traceId is different. Since `X-GDC-TRACE-ID` is in the non-static headers list that gets stripped during matching, that shouldn't cause a mismatch. The real issue is that the traceId in the actual response doesn't match what's in the cassette, which means either the cassette isn't being used or there's something else filtering the response.\n\nActually, wait\u2014with `RecordMode.ONCE`, VCR should replay from the cassette if it exists, but if a request doesn't match any recorded interaction or if there are more requests than recorded, it might fall back", "truncated": true}]} -{"ts": 1778573403.8687866, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the service more broadly and related tests:", "truncated": false}]} -{"ts": 1778573404.6209807, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01MKnRXfZ6MfaCMR5YDs9jHR", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 620, \"limit\": 130}", "truncated": false}]} -{"ts": 1778573404.6631484, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MKnRXfZ6MfaCMR5YDs9jHR", "is_error": false, "content": "620\t llm_provider_patch.id, llm_provider_patch_document.to_api(), _check_return_type=False\n621\t )\n622\t return CatalogLlmProvider.from_api(response.data)\n623\t\n624\t def delete_llm_provider(self, id: str) -> None:\n625\t \"\"\"Delete an LLM provider.\n626\t\n627\t Args:\n628\t id: LLM provider identifier\n629\t \"\"\"\n630\t self._entities_api.delete_entity_llm_providers(id, _check_return_type=False)\n631\t\n632\t # Layout APIs\n633\t\n634\t def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:\n635\t \"\"\"\n636\t Get all declarative notification channels in the current organization.\n637\t\n638\t Returns:\n639\t list[CatalogDeclarativeNotificationChannel]:\n640\t List of declarative notification channels.\n641\t \"\"\"\n642\t return [\n643\t CatalogDeclarativeNotificationChannel.from_api(nc)\n644\t for nc in self._layout_api.get_notification_channels_layout().notification_channels\n645\t ]\n646\t\n647\t def put_declarative_notification_channels(\n648\t self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n649\t ) -> None:\n650\t \"\"\"\n651\t Put declarative notification channels in the current organization.\n652\t\n653\t Args:\n654\t notification_channels (list[CatalogDeclarativeNotificationChannel]):\n655\t List of declarative notification channels.\n656\t\n657\t Returns:\n658\t None\n659\t \"\"\"\n660\t api_ncs = [nc.to_api() for nc in notification_channels]\n661\t self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n662\t\n663\t def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:\n664\t \"\"\"\n665\t Get all declarative identity providers in the current organization.\n666\t\n667\t Returns:\n668\t list[CatalogDeclarativeIdentit", "truncated": true}]} -{"ts": 1778573430.7477183, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern clearly! For `notification_channels`, `identity_providers`, and `export_templates`, each has a DEDICATED API endpoint:\n- `get_notification_channels_layout()` / `set_notification_channels()`\n- `get_identity_providers_layout()` / `set_identity_providers()`\n- `get_export_templates_layout()` / `set_export_templates()`\n\nThese are all targeted endpoints that DON'T affect other org layout parts.\n\nBut for `ip_allowlist_policies`, there's NO dedicated endpoint! The only way to access them is through the full `get/set_organization_layout`.\n\n\nThe read-modify-write pattern breaks because the GET returns masked passwords in data sources, but the PUT rejects them if there's a username without a password. The real question is whether I can strip out the data sources entirely before sending the PUT\u2014but that only works if the server doesn't delete them when they're missing from the request.\n\nLooking at the endpoint semantics, this is a declarative PUT that likely replaces all entities, which means omitting data sources would probably delete them. That's risky. Alternatively, maybe the server uses PATCH semantics and only updates what's included? The cassette shows a 400 error when the PUT body contains data sources with username but no password, so the server is validating the structure. Even removing just the username field wouldn't help\u2014the server probably requires both username and password together for USERNAME_PASSWORD authentication.\n\nI'm wondering if there's a separate `put_data_sources_layout` endpoint that handles data sources independently, which would let me avoid sending them in the organization layout PUT altogether. I need to decide on the fix: remove `data_sources` from the org layout before PUTting it, swap the test user to `demo2` and the group to `demoGroup` (both of which exist in the cassette), and delete the stale cassette so it gets re-recorded. But I'm wondering if removing the data sources will actually work, or if there's something else", "truncated": true}]} -{"ts": 1778573430.7515438, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the `set_organization_layout` endpoint definition in the generated client to understand the expected request body:", "truncated": false}]} -{"ts": 1778573431.8523152, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01K7wUW1PvC1gwGxwavqxVK4", "input": "{\"pattern\": \"set_organization_layout_endpoint|organizationLayout|data_source\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50, \"offset\": 5870}", "truncated": false}]} -{"ts": 1778573432.1605437, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01K7wUW1PvC1gwGxwavqxVK4", "is_error": false, "content": "No matches found\n\n[Showing results with pagination = offset: 5870]", "truncated": false}]} -{"ts": 1778573432.161245, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_014V9m7nGcE977Hqc4KiRgmU", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\"}", "truncated": false}]} -{"ts": 1778573432.1945355, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014V9m7nGcE977Hqc4KiRgmU", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_cl", "truncated": false}]} -{"ts": 1778573434.3087003, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NrBbt2jXFaNogoBKWnQXB3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 6450, \"limit\": 80}", "truncated": false}]} -{"ts": 1778573434.3424428, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NrBbt2jXFaNogoBKWnQXB3", "is_error": false, "content": "6450\t )\n6451\t kwargs['_check_return_type'] = kwargs.get(\n6452\t '_check_return_type', True\n6453\t )\n6454\t kwargs['_spec_property_naming'] = kwargs.get(\n6455\t '_spec_property_naming', False\n6456\t )\n6457\t kwargs['_content_type'] = kwargs.get(\n6458\t '_content_type')\n6459\t kwargs['_host_index'] = kwargs.get('_host_index')\n6460\t kwargs['_request_auths'] = kwargs.get('_request_auths', None)\n6461\t kwargs['workspace_id'] = \\\n6462\t workspace_id\n6463\t kwargs['declarative_workspace_permissions'] = \\\n6464\t declarative_workspace_permissions\n6465\t return self.set_workspace_permissions_endpoint.call_with_http_info(**kwargs)\n6466\t\n6467\t def set_workspaces_layout(\n6468\t self,\n6469\t declarative_workspaces,\n6470\t **kwargs\n6471\t ):\n6472\t \"\"\"Set all workspaces layout # noqa: E501\n6473\t\n6474\t Sets complete layout of workspaces, their hierarchy, models. # noqa: E501\n6475\t This method makes a synchronous HTTP request by default. To make an\n6476\t asynchronous HTTP request, please pass async_req=True\n6477\t\n6478\t >>> thread = api.set_workspaces_layout(declarative_workspaces, async_req=True)\n6479\t >>> result = thread.get()\n6480\t\n6481\t Args:\n6482\t declarative_workspaces (DeclarativeWorkspaces):\n6483\t\n6484\t Keyword Args:\n6485\t _return_http_data_only (bool): response data without head status\n6486\t code and headers. Default is True.\n6487\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n6488\t will be returned without reading/decoding response data.\n6489\t Default is True.\n6490\t _request_timeout (int/float/tuple): timeout setting for this request. If\n6491\t one number provided, it will be total request timeout. It can also\n6492\t be a pair (tuple) of (conn", "truncated": true}]} -{"ts": 1778573438.0769076, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I need to understand what happens when `data_sources` is omitted from the `set_organization_layout` PUT. Let me look at how the ModelNormal object is serialized in the API client. When we call `set_organization_layout(org_layout)`, it serializes the org_layout object to JSON. If we delete `data_sources` from the org_layout object, it won't be included in the JSON.\n\nActually, let me look at the GoodData documentation or schemas to understand if `set_organization_layout` accepts data sources.\n\nLet me look at the OpenAPI schema:", "truncated": false}]} -{"ts": 1778573438.6275938, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LFJRJYe4tNaED3AE8agWbL", "input": "{\"pattern\": \"**/openapi*.json\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} -{"ts": 1778573438.647309, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LFJRJYe4tNaED3AE8agWbL", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778573439.0766628, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01W4e4HNYD1WjbpZWHuZYaMo", "input": "{\"pattern\": \"**/*.yaml\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} -{"ts": 1778573439.1250844, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01W4e4HNYD1WjbpZWHuZYaMo", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778573440.8725183, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01RuphSpJKEP3WM9topeCAgh", "input": "{\"pattern\": \"**/*.json\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas\"}", "truncated": false}]} -{"ts": 1778573440.9493003, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01RuphSpJKEP3WM9topeCAgh", "is_error": false, "content": "schemas/gooddata-afm-client.json\nschemas/gooddata-api-client.json\nschemas/gooddata-automation-client.json\nschemas/gooddata-export-client.json\nschemas/gooddata-metadata-client.json\nschemas/gooddata-result-client.json\nschemas/gooddata-scan-client.json", "truncated": false}]} -{"ts": 1778573445.4138584, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Agent", "id": "toolu_01HVGT66PbvTDfV2X1iXzZBN", "input": "{\"description\": \"Find set_organization_layout request schema\", \"subagent_type\": \"Explore\", \"prompt\": \"In the file /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json, find the definition of the `set_organization_layout` operation (likely under /api/v1/layout/organization PUT). Look for:\\n1. The request body schema - what fields does it accept?\\n2. Is `dataSources` a required field or optional?\\n3. What happens if dataSources is omitted?\\n\\nAlso search for any documentation string like \\\"Sets complete layout\\\" to find the relevant endpoint.\\n\\nQuick search - just look at the PUT /layout/organization operation definition. Report back what fields are in the request body schema (DeclarativeOrganization) and whether data_sources is required.\"}", "truncated": false}]} -{"ts": 1778573445.457617, "type": "system"} -{"ts": 1778573445.4577394, "type": "user", "blocks": [{"type": "text", "text": "In the file /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json, find the definition of the `set_organization_layout` operation (likely under /api/v1/layout/organization PUT). Look for:\n1. The request body schema - what fields does it accept?\n2. Is `dataSources` a required field or optional?\n3. What happens if dataSources is omitted?\n\nAlso search for any documentation string like \"Sets complete layout\" to find the relevant endpoint.\n\nQuick search - just look at the PUT /layout/organization operation definition. Report back what fields are in the request body schema (DeclarativeOrganization) and whether data_sources is required.", "truncated": false}]} -{"ts": 1778573447.096374, "type": "system"} -{"ts": 1778573447.0965405, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Tzv5YYVqFVuV4H4ZXb7AAk", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"limit\": 100}", "truncated": false}]} -{"ts": 1778573447.2999392, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Tzv5YYVqFVuV4H4ZXb7AAk", "is_error": false, "content": "1\t{\n2\t \"components\": {\n3\t \"parameters\": {\n4\t \"idPathParameter\": {\n5\t \"in\": \"path\",\n6\t \"name\": \"id\",\n7\t \"required\": true,\n8\t \"schema\": {\n9\t \"pattern\": \"^(?!\\\\.)[.A-Za-z0-9_-]{1,255}$\",\n10\t \"type\": \"string\"\n11\t }\n12\t },\n13\t \"page\": {\n14\t \"description\": \"Zero-based page index (0..N)\",\n15\t \"in\": \"query\",\n16\t \"name\": \"page\",\n17\t \"schema\": {\n18\t \"default\": 0,\n19\t \"type\": \"integer\"\n20\t }\n21\t },\n22\t \"size\": {\n23\t \"description\": \"The size of the page to be returned\",\n24\t \"in\": \"query\",\n25\t \"name\": \"size\",\n26\t \"schema\": {\n27\t \"default\": 20,\n28\t \"type\": \"integer\"\n29\t }\n30\t },\n31\t \"sort\": {\n32\t \"description\": \"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.\",\n33\t \"in\": \"query\",\n34\t \"name\": \"sort\",\n35\t \"schema\": {\n36\t \"items\": {\n37\t \"type\": \"string\"\n38\t },\n39\t \"type\": \"array\"\n40\t }\n41\t }\n42\t },\n43\t \"responses\": {\n44\t \"Deleted\": {\n45\t \"description\": \"Successfully deleted\"\n46\t }\n47\t },\n48\t \"schemas\": {\n49\t \"AFM\": {\n50\t \"description\": \"Top level executable entity. Combination of [A]ttributes, [F]ilters & [M]etrics.\",\n51\t \"properties\": {\n52\t \"attributes\": {\n53\t \"description\": \"Attributes to be used in the computation.\",\n54\t \"items\": {\n55\t \"$ref\": \"#/components/schemas/AttributeItem\"\n56\t },\n57\t \"type\": \"array\"\n58\t },\n59\t \"auxMeasures\": {\n60\t \"description\": \"Metrics to be referenced from other AFM objects (e.g. filters) but not included in the result.\",\n61\t \"items\": {\n62\t \"$ref\": \"#/components/schemas/MeasureItem\"\n63\t },\n64\t \"type\": \"array\"\n65\t ", "truncated": true}]} -{"ts": 1778573447.3045278, "type": "system"} -{"ts": 1778573447.3046682, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_0158euZCKUW1wvNFFWSAcvwn", "input": "{\"command\": \"grep -n \\\"set_organization_layout\\\\|/api/v1/layout/organization\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json | head -20\"}", "truncated": false}]} -{"ts": 1778573447.340812, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0158euZCKUW1wvNFFWSAcvwn", "is_error": true, "content": "Blocked: grep -n \"set_organization_layout\\|/api/v1/layout/organization\" /home/runner/_wor", "truncated": false}]} -{"ts": 1778573450.0718591, "type": "system"} -{"ts": 1778573450.072006, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_015zNBEYdVdUc886BeSKKc4s", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\"}", "truncated": false}]} -{"ts": 1778573450.1048636, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015zNBEYdVdUc886BeSKKc4s", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json", "truncated": false}]} -{"ts": 1778573451.6276126, "type": "system"} -{"ts": 1778573451.6277678, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01A4GjxJyyy7G3t2cBdxD5cN", "input": "{\"pattern\": \"layout/organization|set_organization_layout|Sets complete layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"content\"}", "truncated": false}]} -{"ts": 1778573451.6587243, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01A4GjxJyyy7G3t2cBdxD5cN", "is_error": false, "content": "64785: \"/api/v1/layout/organization\": {\n64831: \"description\": \"Sets complete layout of organization, like workspaces, user-groups, etc.\",\n64861: \"/api/v1/layout/organization/permissions\": {\n65367: \"description\": \"Sets complete layout of workspaces, their hierarchy, models.\",", "truncated": false}]} -{"ts": 1778573453.0330114, "type": "system"} -{"ts": 1778573453.0331602, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01WfnptckTScd2rkNeWmAbww", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"offset\": 64785, \"limit\": 100}", "truncated": false}]} -{"ts": 1778573453.065535, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WfnptckTScd2rkNeWmAbww", "is_error": false, "content": "64785\t \"/api/v1/layout/organization\": {\n64786\t \"get\": {\n64787\t \"description\": \"Retrieve complete layout of organization, workspaces, user-groups, etc.\",\n64788\t \"operationId\": \"getOrganizationLayout\",\n64789\t \"parameters\": [\n64790\t {\n64791\t \"in\": \"query\",\n64792\t \"name\": \"exclude\",\n64793\t \"required\": false,\n64794\t \"schema\": {\n64795\t \"items\": {\n64796\t \"description\": \"Defines properties which should not be included in the payload.\",\n64797\t \"enum\": [\n64798\t \"ACTIVITY_INFO\"\n64799\t ],\n64800\t \"type\": \"string\"\n64801\t },\n64802\t \"type\": \"array\"\n64803\t }\n64804\t }\n64805\t ],\n64806\t \"responses\": {\n64807\t \"200\": {\n64808\t \"content\": {\n64809\t \"application/json\": {\n64810\t \"schema\": {\n64811\t \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64812\t }\n64813\t }\n64814\t },\n64815\t \"description\": \"Retrieved all parts of an organization.\"\n64816\t }\n64817\t },\n64818\t \"summary\": \"Get organization layout\",\n64819\t \"tags\": [\n64820\t \"layout\",\n64821\t \"Organization - Declarative APIs\"\n64822\t ],\n64823\t \"x-gdc-security-info\": {\n64824\t \"description\": \"Permission required to get organization layout.\",\n64825\t \"permissions\": [\n64826\t \"MANAGE\"\n64827\t ]\n64828\t }\n64829\t },\n64830\t \"put\": {\n64831\t \"description\": \"Sets complete layout of organization, like workspaces, user-groups, etc.\",\n64832\t \"operationId\": \"setOrganizationLayout\",\n64833\t \"requestBody\": {\n64834\t \"content\": {\n64835\t \"application/json\": {\n64836\t \"schema\": {\n64837\t \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n648", "truncated": true}]} -{"ts": 1778573455.2271101, "type": "system"} -{"ts": 1778573455.2272766, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_018HUB8ZRTKV7NJZvRGYHEvN", "input": "{\"pattern\": \"\\\"DeclarativeOrganization\\\":\\\\s*\\\\{\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"files_with_matches\"}", "truncated": false}]} -{"ts": 1778573455.2667735, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018HUB8ZRTKV7NJZvRGYHEvN", "is_error": false, "content": "Found 1 file\nschemas/gooddata-api-client.json", "truncated": false}]} -{"ts": 1778573456.8281085, "type": "system"} -{"ts": 1778573456.828594, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_018NnAAPHNdjEWs79CLP8ayJ", "input": "{\"pattern\": \"DeclarativeOrganization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} -{"ts": 1778573456.8667054, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018NnAAPHNdjEWs79CLP8ayJ", "is_error": false, "content": "7301: \"DeclarativeOrganization\": {\n7353: \"$ref\": \"#/components/schemas/DeclarativeOrganizationInfo\"\n7385: \"DeclarativeOrganizationInfo\": {\n7446: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"\n7473: \"DeclarativeOrganizationPermission\": {\n64811: \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64837: \"$ref\": \"#/components/schemas/DeclarativeOrganization\"\n64871: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"\n64901: \"$ref\": \"#/components/schemas/DeclarativeOrganizationPermission\"", "truncated": false}]} -{"ts": 1778573458.093222, "type": "system"} -{"ts": 1778573458.093363, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01FZzt6yj36H9DK5a2kFwPMg", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json\", \"offset\": 7301, \"limit\": 100}", "truncated": false}]} -{"ts": 1778573458.123855, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01FZzt6yj36H9DK5a2kFwPMg", "is_error": false, "content": "7301\t \"DeclarativeOrganization\": {\n7302\t \"description\": \"Complete definition of an organization in a declarative form.\",\n7303\t \"properties\": {\n7304\t \"agents\": {\n7305\t \"items\": {\n7306\t \"$ref\": \"#/components/schemas/DeclarativeAgent\"\n7307\t },\n7308\t \"type\": \"array\"\n7309\t },\n7310\t \"customGeoCollections\": {\n7311\t \"items\": {\n7312\t \"$ref\": \"#/components/schemas/DeclarativeCustomGeoCollection\"\n7313\t },\n7314\t \"type\": \"array\"\n7315\t },\n7316\t \"dataSources\": {\n7317\t \"items\": {\n7318\t \"$ref\": \"#/components/schemas/DeclarativeDataSource\"\n7319\t },\n7320\t \"type\": \"array\"\n7321\t },\n7322\t \"exportTemplates\": {\n7323\t \"items\": {\n7324\t \"$ref\": \"#/components/schemas/DeclarativeExportTemplate\"\n7325\t },\n7326\t \"type\": \"array\"\n7327\t },\n7328\t \"identityProviders\": {\n7329\t \"items\": {\n7330\t \"$ref\": \"#/components/schemas/DeclarativeIdentityProvider\"\n7331\t },\n7332\t \"type\": \"array\"\n7333\t },\n7334\t \"ipAllowlistPolicies\": {\n7335\t \"items\": {\n7336\t \"$ref\": \"#/components/schemas/DeclarativeIpAllowlistPolicy\"\n7337\t },\n7338\t \"type\": \"array\"\n7339\t },\n7340\t \"jwks\": {\n7341\t \"items\": {\n7342\t \"$ref\": \"#/components/schemas/DeclarativeJwk\"\n7343\t },\n7344\t \"type\": \"array\"\n7345\t },\n7346\t \"notificationChannels\": {\n7347\t \"items\": {\n7348\t \"$ref\": \"#/components/schemas/DeclarativeNotificationChannel\"\n7349\t },\n7350\t \"type\": \"array\"\n7351\t },\n7352\t \"organization\": {\n7353\t \"$ref\": \"#/components/schemas/DeclarativeOrganizationInfo\"\n7354\t },\n7355\t \"userGroups\": {\n7356\t ", "truncated": true}]} -{"ts": 1778573462.5523498, "type": "system"} -{"ts": 1778573462.552546, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HVGT66PbvTDfV2X1iXzZBN", "is_error": false, "content": "[{\"type\": \"text\", \"text\": \"Perfect! I have all the information needed. Let me provide you with the findings:\\n\\n## Summary\\n\\n**Operation:** PUT `/api/v1/layout/organization` (operationId: `setOrganizationLayout`)\\n\\n**Request Body Schema:** The PUT endpoint accepts a `DeclarativeOrganization` object.\\n\\n**Fields in DeclarativeOrganization:**\\n1. `agents` (optional) - array\\n2. `customGeoCollections` (optional) - array\\n3. `dataSources` (optional) - array of DeclarativeDataSource objects\\n4. `exportTemplates` (optional) - array\\n5. `identityProviders` (optional) - array\\n6. `ipAllowlistPolicies` (optional) - array\\n7. `jwks` (optional) - array\\n8. `notificationChannels` (optional) - array\\n9. `organization` (required) - DeclarativeOrganizationInfo object\\n10. `userGroups` (optional) - array\\n11. `users` (optional) - array\\n12. `workspaceDataFilters` (optional) - array\\n13. `workspaces` (optional) - array\\n\\n**Is `dataSources` Required?** **NO** - it is optional. The only required field in `DeclarativeOrganization` is `organization` (line 7380-7381 shows `\\\"required\\\": [\\\"organization\\\"]`).\\n\\n**What happens if dataSources is omitted?** If `dataSources` is omitted, the request will still be valid as long as the `organization` field is provided. The endpoint will process the organization layout without updating/setting any data sources.\\n\\n**File location:** `/home/runner/_work/gdc-nas/gdc-nas/sdk/schemas/gooddata-api-client.json`\\n- PUT operation definition: lines 64830-64859\\n- DeclarativeOrganization schema: lines 7301-7383\"}]", "truncated": false}]} -{"ts": 1778573513.3000798, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "`dataSources` is optional in the `set_organization_layout` request. The question is still: if `dataSources` is omitted, does the server:\n1. Delete all existing data sources (treats omission as \"empty list\"), or\n2. Keep existing data sources unchanged (treats omission as \"no change\")\n\nThe schema says it's optional, but that only tells us the request is valid without it. The server behavior (whether it deletes or preserves existing datasources) depends on the API implementation.\n\nLooking at the description: \"Sets complete layout of organization\". If it sets the COMPLETE layout, omitting data sources might delete them.\n\n\nHowever, there's a dedicated `put_data_sources_layout` endpoint, which suggests data sources have their own lifecycle and aren't managed through `set_organization_layout`. The VCR utilities strip environment-specific fields like passwords and URLs from request bodies for matching, but these are still included in actual requests. The real issue is that the test fails when including the datasource with incomplete auth, returning a 400 error\u2014so removing it from the PUT request might be the fix.\n\nLet me check if other tests use `set_organization_layout` to see if omitting datasources is safe, and I should also look at the conftest to understand how the session snapshot mechanism works. The warning about restoring snapshots suggests the test environment can recover from accidental deletions anyway.\n\nI'll take a pragmatic approach: remove `data_sources` from the org_layout object before the PUT request using a safe check, and update the test to use valid credentials like `demo2` and `demoGroup` instead of the invalid ones.\n\nLooking at the cassette data, I can see which users and groups actually exist in the test environment, but the real issue is that the cassette was recorded against the `default` org while the live server uses `python-sdk-dex`, and they likely have different user sets. The error confirms `employee123` doesn't exist in `python-sdk-dex`, so ", "truncated": true}]} -{"ts": 1778573513.3002434, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at other organization layout tests to understand patterns:", "truncated": false}]} -{"ts": 1778573513.8653922, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01NpjExXaqjXfVaD8f6gjgfg", "input": "{\"pattern\": \"layout_organization|organization_layout|set_organization|declarative_organization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} -{"ts": 1778573514.2154393, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NpjExXaqjXfVaD8f6gjgfg", "is_error": false, "content": "packages/gooddata-sdk/tests/conftest.py:263: snapshot[\"org_permissions\"] = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/conftest.py:330: sdk.catalog_permission.put_declarative_organization_permissions(snapshot[\"org_permissions\"])\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:71: sdk.catalog_permission.put_declarative_organization_permissions([default_catalog_organization_permission])\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:73: catalog_permissions = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:198:@gd_vcr.use_cassette(str(_fixtures_dir / \"put_declarative_organization_permissions.yaml\"))\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:199:def test_put_and_get_declarative_organization_permissions(test_config, snapshot_org_permissions):\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:200: expected_json_path = _current_dir / \"expected\" / \"declarative_organization_permissions.json\"\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:206: declarative_organization_permissions = [\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:211: sdk.catalog_permission.put_declarative_organization_permissions(declarative_organization_permissions)\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:213: catalog_declarative_permissions_after_put = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/test_catalog_permission.py:239: catalog_declarative_permissions_initial = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/conftest.py:191: original = sdk.catalog_permission.get_declarative_organization_permissions()\npackages/gooddata-sdk/tests/catalog/conftest.py:198: sdk.catalog_permission.put_", "truncated": true}]} -{"ts": 1778573514.4718747, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NnPhHMKEN9Hx4TgsLbtJvX", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 280, \"limit\": 30}", "truncated": false}]} -{"ts": 1778573514.5075514, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NnPhHMKEN9Hx4TgsLbtJvX", "is_error": false, "content": "280\t except Exception as e:\n281\t logger.error(f\"Snapshot capture failed [workspace list for permissions]: {e}\")\n282\t snapshot[\"ws_permissions\"] = ws_permissions\n283\t\n284\t logger.info(\"Session snapshot captured\")\n285\t\n286\t # --- Tests run ---\n287\t yield snapshot\n288\t\n289\t # --- Restore (only if failures) ---\n290\t if not _session_has_failures:\n291\t logger.info(\"All tests passed \u2014 skipping session restore\")\n292\t return\n293\t\n294\t logger.warning(\"Test failures detected \u2014 restoring session snapshot...\")\n295\t\n296\t # Restore order matters: users/groups \u2192 data sources \u2192 workspaces \u2192\n297\t # workspace data filters \u2192 org permissions \u2192 notification channels \u2192\n298\t # per-workspace permissions\n299\t\n300\t if \"users_groups\" in snapshot:\n301\t try:\n302\t sdk.catalog_user.put_declarative_users_user_groups(snapshot[\"users_groups\"])\n303\t logger.info(\"Restored [users_groups]\")\n304\t except Exception as e:\n305\t logger.error(f\"RESTORE FAILED [users_groups]: {e}\")\n306\t\n307\t if \"data_sources\" in snapshot:\n308\t try:\n309\t sdk.catalog_data_source.put_declarative_data_sources(snapshot[\"data_sources\"], _credentials_path)", "truncated": false}]} -{"ts": 1778573517.0844796, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GQgnaxgpq2exB292aVd9b3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 200, \"limit\": 80}", "truncated": false}]} -{"ts": 1778573517.1163845, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GQgnaxgpq2exB292aVd9b3", "is_error": false, "content": "200\t Layout files are stored under gooddata_layouts/default/. On staging, the SDK\n201\t resolves org_id to the real staging value. Symlinks make both paths point to\n202\t the same directory.\n203\t \"\"\"\n204\t org_id = test_config.get(\"org_id\", \"default\")\n205\t symlinks_created = []\n206\t if org_id != \"default\":\n207\t for layout_root in _LAYOUT_ROOTS:\n208\t symlink = layout_root / org_id\n209\t if not symlink.exists():\n210\t symlink.symlink_to(\"default\")\n211\t symlinks_created.append(symlink)\n212\t logger.info(f\"Created org_id symlinks for '{org_id}'\")\n213\t\n214\t yield\n215\t\n216\t for symlink in symlinks_created:\n217\t symlink.unlink(missing_ok=True)\n218\t\n219\t\n220\t# ---------------------------------------------------------------------------\n221\t# Session-level snapshot/restore \u2014 safety net for staging\n222\t# ---------------------------------------------------------------------------\n223\t\n224\t\n225\t@pytest.fixture(scope=\"session\", autouse=True)\n226\tdef staging_session_snapshot(test_config, staging_preflight):\n227\t \"\"\"When staging: true, capture full environment state before tests run.\n228\t\n229\t On teardown, if any test failed, restore everything to the captured state.\n230\t This is the last line of defense \u2014 per-test snapshot fixtures are the first.\n231\t \"\"\"\n232\t if not test_config.get(\"staging\", False):\n233\t yield\n234\t return\n235\t\n236\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n237\t\n238\t # --- Capture ---\n239\t snapshot = {}\n240\t logger.info(\"Capturing session snapshot...\")\n241\t\n242\t try:\n243\t snapshot[\"users_groups\"] = sdk.catalog_user.get_declarative_users_user_groups()\n244\t except Exception as e:\n245\t logger.error(f\"Snapshot capture failed [users_groups]: {e}\")\n246\t\n247\t try:\n248\t snapshot[\"data_sources\"] = sdk.catalog_data_source.get_declarative_data_sources()\n249\t except Excep", "truncated": true}]} -{"ts": 1778573548.3740118, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see! The conftest snapshot captures:\n1. `users_groups`\n2. `data_sources` (via `get_declarative_data_sources`) \n3. `workspaces`\n4. `workspace_data_filters`\n5. `org_permissions`\n6. `notification_channels`\n7. Per-workspace permissions\n\nNotice that `ip_allowlist_policies` is NOT in the snapshot. The conftest doesn't snapshot/restore IP allowlist policies. This means if our test accidentally modifies them and fails to restore, they won't be restored by the session snapshot.\n\n\nThe conftest also uses a separate API for data sources\u2014`get_declarative_data_sources` and `put_declarative_data_sources`\u2014rather than managing them through `set_organization_layout`. This separation strongly suggests that `set_organization_layout` doesn't control data sources, so omitting them from a PUT request wouldn't delete existing ones.\n\nMy approach is to remove `data_sources` from the org layout object before PUTting it in `put_declarative_ip_allowlist_policies`, update the test values to use `demo2` and `demoGroup`, and delete the stale cassette so it gets re-recorded. Now I need to figure out how to strip `data_sources` from a ModelNormal instance and understand what type `get_organization_layout` returns when type checking is disabled.\n\nWith `_check_return_type=False`, I get a ModelNormal instance where attributes are accessed and modified through regular attribute assignment. The real question is whether setting `data_sources` to an empty list would work, but the server's validation error suggests it actually processes the `data_sources` field in the PUT request rather than ignoring it. This means I can't just pass an empty list\u2014I need to actually remove the field entirely from the request body. The server is rejecting the PUT because the datasource auth is incomplete, which means it's actively validating data sources rather than ignoring them. The `_ENV_SPECIFIC_BODY_FIELDS` mechanism strips environment-specific credentials from VCR matching, so the intended pattern is to include d", "truncated": true}]} -{"ts": 1778573548.3741748, "type": "assistant", "blocks": [{"type": "text", "text": "Let me understand how ModelNormal handles attribute deletion and look at existing tests that do similar read-modify-write operations:", "truncated": false}]} -{"ts": 1778573549.4657626, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DjBDHHyW3vZeum8jugFPDA", "input": "{\"pattern\": \"_data_store|__delattr__|__setattr__\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model_utils.py\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} -{"ts": 1778573549.9656549, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DjBDHHyW3vZeum8jugFPDA", "is_error": false, "content": "176: self.__dict__['_data_store'][name] = value\n186: def __setattr__(self, attr, value):\n465: return self.__dict__['_data_store'].get(name, default)\n483: return name in self.__dict__['_data_store']\n494: this_val = self._data_store['value']\n495: that_val = other._data_store['value']\n520: return self.__dict__['_data_store'].get(name, default)\n538: return name in self.__dict__['_data_store']\n558: if not set(self._data_store.keys()) == set(other._data_store.keys()):\n560: for _var_name, this_val in self._data_store.items():\n561: that_val = other._data_store[_var_name]\n589: they are returned from the self._data_store or the data stores in the instances\n658: if name in model_instance._data_store:\n659: v = model_instance._data_store[name]\n697: if name in model_instance._data_store:\n720: if not set(self._data_store.keys()) == set(other._data_store.keys()):\n722: for _var_name, this_val in self._data_store.items():\n723: that_val = other._data_store[_var_name]\n1684: extract_item = lambda item: (item[0], model_to_dict(item[1], serialize=serialize)) if hasattr(item[1], '_data_store') else item\n1693: for attr, value in model_instance._data_store.items():\n1729: elif hasattr(value, '_data_store'):", "truncated": false}]} -{"ts": 1778573549.9972496, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01QeHe69ScxvYp59VFxs4j7a", "input": "{\"pattern\": \"**/catalog_data_source_service.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src\"}", "truncated": false}]} -{"ts": 1778573550.0580559, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QeHe69ScxvYp59VFxs4j7a", "is_error": false, "content": "No files found", "truncated": false}]} -{"ts": 1778573552.4546952, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GhjRjvSZcjPj3UnC61u3AG", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model_utils.py\", \"offset\": 170, \"limit\": 40}", "truncated": false}]} From 077603e93942cea3b9b50a17dd0a2ecc3fe085d9 Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Wed, 13 May 2026 07:41:57 +0000 Subject: [PATCH 5/6] fix(gooddata-sdk): [AUTO] fix-agent attempt 1 --- .../layout_ip_allowlist_policies.yaml | 10745 ++++++++++++++++ transcripts/fix-C009-attempt1.jsonl | 125 + 2 files changed, 10870 insertions(+) create mode 100644 packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml create mode 100644 transcripts/fix-C009-attempt1.jsonl diff --git a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml new file mode 100644 index 000000000..b5ef807d8 --- /dev/null +++ b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml @@ -0,0 +1,10745 @@ +interactions: + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: + - allowedSources: + - 203.0.113.10/32 + - 198.51.100.0/24 + id: admin-vpn-only + userGroups: + - id: adminGroup + type: userGroup + users: + - id: demo + type: user + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request +version: 1 diff --git a/transcripts/fix-C009-attempt1.jsonl b/transcripts/fix-C009-attempt1.jsonl new file mode 100644 index 000000000..98415cb87 --- /dev/null +++ b/transcripts/fix-C009-attempt1.jsonl @@ -0,0 +1,125 @@ +{"ts": 1778657705.926109, "type": "system"} +{"ts": 1778657707.6267068, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me start by understanding the failing test and the code involved to figure out what needs to be fixed.", "truncated": false}]} +{"ts": 1778657708.555351, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01V1xi1HNZ3ijhWzf8xz9TX7", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 570, \"limit\": 60}", "truncated": false}]} +{"ts": 1778657708.966267, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01V1xi1HNZ3ijhWzf8xz9TX7", "is_error": false, "content": "570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"adminGroup\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"demo\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"adminGroup\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"demo\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} +{"ts": 1778657708.966795, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_014ybk7p2xDy5eXsMrKQe3fS", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/**/*.py\"}", "truncated": false}]} +{"ts": 1778657708.9997265, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014ybk7p2xDy5eXsMrKQe3fS", "is_error": false, "content": "packages/gooddata-sdk/src/gooddata_sdk/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/_version.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/ai_lake/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/ai_lake/service.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/appearance/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/appearance/entity_model/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/appearance/entity_model/color_palette.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/appearance/entity_model/theme.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/appearance/service.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/base.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/catalog_service_base.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/requests/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/requests/ldm_request.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/requests/scan_model_request.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/requests/scan_sql_request.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/responses/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/responses/scan_sql_response.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/action_model/sql_column.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/declarative_model/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/declarative_model/data_source.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/declarative_model/physical_model/__init__.py\npackages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/declarative_mod", "truncated": true}]} +{"ts": 1778657714.121351, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look at the test more carefully and the service implementation to understand what's happening.", "truncated": false}]} +{"ts": 1778657715.0583978, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01UPHpLuFFtCwhpxD1qZTZ4G", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 750, \"limit\": 60}", "truncated": false}]} +{"ts": 1778657715.4865263, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UPHpLuFFtCwhpxD1qZTZ4G", "is_error": false, "content": "750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} +{"ts": 1778657715.8553169, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01EE32v8poAvJ5HCNas8tcKb", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/layout/ip_allowlist_policy.py\"}", "truncated": false}]} +{"ts": 1778657715.9019704, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01EE32v8poAvJ5HCNas8tcKb", "is_error": false, "content": "1\t# (C) 2025 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\t\n6\tfrom attrs import define, field\n7\tfrom gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy\n8\t\n9\tfrom gooddata_sdk.catalog.base import Base\n10\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n11\t\n12\t\n13\t@define(kw_only=True)\n14\tclass CatalogDeclarativeIpAllowlistPolicy(Base):\n15\t id: str\n16\t allowed_sources: list[str] = field(factory=list)\n17\t user_groups: list[CatalogDeclarativeUserGroupIdentifier] = field(factory=list)\n18\t users: list[CatalogUserIdentifier] = field(factory=list)\n19\t\n20\t @staticmethod\n21\t def client_class() -> builtins.type[DeclarativeIpAllowlistPolicy]:\n22\t return DeclarativeIpAllowlistPolicy\n23\t", "truncated": false}]} +{"ts": 1778657731.4571333, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The error is:\n```\nHTTP response body: {\"detail\":\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \",\"status\":400,\"title\":\"Bad Request\",\"traceId\":\"63741292b6fb78b580ca7a5aec9de811\"}\n```\n\nThis is interesting - the error mentions \"Invalid combination of auth properties\" for a data source. This happens when the test tries to restore the original policies via `put_declarative_ip_allowlist_policies(original_policies)`.\n \nSo the issue is that when `put_declarative_ip_allowlist_policies` reads and writes back the full org layout, it's also writing the data source configurations. The demo-test-ds data source has an invalid auth setup - it has a username but no password, which violates the auth property rules. The `set_organization_layout` call is failing because it's trying to persist this invalid configuration. The root cause is that when the method retrieves the org layout, data source passwords are redacted for security, but the subsequent PUT request fails validation because it requires either complete credential pairs or nothing at all. I should check how other methods in the service handle this credential stripping problem.", "truncated": false}]} +{"ts": 1778657731.4607584, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01TwnSKrwXdsCWrRXqU9QqWJ", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 1, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657731.4805062, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TwnSKrwXdsCWrRXqU9QqWJ", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport functools\n5\tfrom typing import Any, Literal\n6\t\n7\tfrom gooddata_api_client.exceptions import NotFoundException\n8\tfrom gooddata_api_client.model.declarative_export_templates import DeclarativeExportTemplates\n9\tfrom gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n10\tfrom gooddata_api_client.model.json_api_csp_directive_in_document import JsonApiCspDirectiveInDocument\n11\tfrom gooddata_api_client.model.json_api_export_template_in_document import JsonApiExportTemplateInDocument\n12\tfrom gooddata_api_client.model.json_api_export_template_post_optional_id_document import (\n13\t JsonApiExportTemplatePostOptionalIdDocument,\n14\t)\n15\tfrom gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument\n16\tfrom gooddata_api_client.model.json_api_organization_patch import JsonApiOrganizationPatch\n17\tfrom gooddata_api_client.model.json_api_organization_patch_document import JsonApiOrganizationPatchDocument\n18\tfrom gooddata_api_client.model.json_api_organization_setting_in_document import JsonApiOrganizationSettingInDocument\n19\tfrom gooddata_api_client.model.switch_identity_provider_request import SwitchIdentityProviderRequest\n20\t\n21\tfrom gooddata_sdk import CatalogDeclarativeExportTemplate, CatalogExportTemplate\n22\tfrom gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase\n23\tfrom gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective\n24\tfrom gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider\n25\tfrom gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument\n26\tfrom gooddata_sdk.catalog.organization.entity_model.llm_provider import (\n27\t CatalogLlmProvider,\n28\t CatalogLlmProviderDocument,\n29\t CatalogLlmProviderPatch,\n30\t CatalogLlmProviderPatchDocument,\n31\t)\n32\tfrom gooddata_sdk.c", "truncated": true}]} +{"ts": 1778657732.1002498, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01JyocCsmp9bhepMFQH1EE76", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 560, \"limit\": 15}", "truncated": false}]} +{"ts": 1778657732.129557, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JyocCsmp9bhepMFQH1EE76", "is_error": false, "content": "560\t# assert identity_providers_o[0].identifiers == identity_providers_e[0].identifiers\n561\t# assert identity_providers_o[0].oauth_client_id == identity_providers_e[0].oauth_client_id\n562\t# assert identity_providers_o[0].oauth_client_secret is None\n563\t# assert identity_providers_o[0].oauth_issuer_location == identity_providers_e[0].oauth_issuer_location\n564\t# finally:\n565\t# sdk.catalog_organization.put_declarative_identity_providers([])\n566\t# idps = sdk.catalog_organization.get_declarative_identity_providers()\n567\t# assert len(idps) == 0\n568\t\n569\t\n570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()", "truncated": false}]} +{"ts": 1778657754.5471907, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The error is: \"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \"\n\nThis happens when the test restores original_policies by calling `put_declarative_ip_allowlist_policies(original_policies)` which:\n1. GETs the org layout\n2. Replaces ip_allowlist_policies\n\n\n3. PUTs the entire org layout back\n\nThe problem is a classic read-back-write issue: when retrieving the org layout, data sources include credentials like usernames but passwords aren't returned, so PUTting it back fails validation since the username exists without a password. The real culprit might be that the VCR cassette for this test doesn't exist yet since stale cassettes were cleaned up, meaning it's hitting a live server instead of recorded responses. So the issue is that when we GET the organization layout, the data source passwords are stripped for security, but the usernames remain\u2014and when we PUT it back, the API validation fails because it expects either both credentials or neither. I need to either clear out the data source credentials entirely before the PUT, or find a way to preserve the original credentials. Let me check what the organization layout structure looks like and whether there's a cleaner approach than modifying the entire layout just to update IP allowlist policies. But the test is using the installed version.\n\nWait, but the installed version should match the source... Unless the package was installed before the fix was made.\n\nActually looking at line 777 in the installed service.py:\n```\nself._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n```\n\nThis is the same code I see in the source at line 777. So the installed code matches.\n\nThe issue is that the org layout returned by `get_organization_layout` includes data sources with usernames but not passwords. When we PUT the org lay", "truncated": true}]} +{"ts": 1778657754.5714526, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01SFFmtmRgY8pzkatS4M8Gy1", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 730, \"limit\": 50}", "truncated": false}]} +{"ts": 1778657754.6293762, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01SFFmtmRgY8pzkatS4M8Gy1", "is_error": false, "content": "730\t None\n731\t\n732\t Raises:\n733\t ValueError:\n734\t Identity provider does not exist or operation failed.\n735\t \"\"\"\n736\t try:\n737\t request = SwitchIdentityProviderRequest(idp_id=identity_provider_id)\n738\t self._actions_api.switch_active_identity_provider(request, _check_return_type=False)\n739\t\n740\t except NotFoundException:\n741\t raise ValueError(\n742\t f\"Cannot switch to identity provider {identity_provider_id}. This identity provider does not exist.\"\n743\t )\n744\t except Exception as e:\n745\t raise ValueError(f\"Error switching active identity provider: {str(e)}\")\n746\t\n747\t def get_declarative_ip_allowlist_policies(self) -> list[CatalogDeclarativeIpAllowlistPolicy]:\n748\t \"\"\"Get all declarative IP allowlist policies for the current organization.\n749\t\n750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative ", "truncated": true}]} +{"ts": 1778657754.6355796, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Y1hSM51rq2eP3M6Zav2bXv", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} +{"ts": 1778657754.7064903, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Y1hSM51rq2eP3M6Zav2bXv", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\tfrom pathlib import Path\n5\t\n6\tfrom gooddata_api_client.exceptions import NotFoundException\n7\tfrom gooddata_sdk import (\n8\t CatalogCspDirective,\n9\t CatalogDeclarativeIpAllowlistPolicy,\n10\t CatalogDeclarativeNotificationChannel,\n11\t CatalogJwk,\n12\t CatalogOrganization,\n13\t CatalogOrganizationSetting,\n14\t CatalogRsaSpecification,\n15\t CatalogWebhook,\n16\t GoodDataSdk,\n17\t)\n18\tfrom gooddata_sdk.catalog.identifier import CatalogDeclarativeUserGroupIdentifier, CatalogUserIdentifier\n19\tfrom tests_support.vcrpy_utils import get_vcr\n20\t\n21\tfrom .conftest import safe_delete\n22\t\n23\tgd_vcr = get_vcr()\n24\t\n25\t_default_jwk_id = \"demoJwk\"\n26\t_current_dir = Path(__file__).parent.absolute()\n27\t_fixtures_dir = _current_dir / \"fixtures\" / \"organization\"\n28\t\n29\t\n30\tdef _default_organization_check(organization: CatalogOrganization, test_config: dict):\n31\t # Relaxed assertions \u2014 cassettes may come from local or staging environment,\n32\t # so we only verify the fields are populated, not their exact values.\n33\t assert organization.id\n34\t assert organization.attributes.name\n35\t assert organization.attributes.hostname\n36\t\n37\t\n38\tdef _default_jwk(jwk_id=_default_jwk_id, alg=None, kid=None):\n39\t rsa_specification = CatalogRsaSpecification(\n40\t alg=alg if alg else \"RS256\",\n41\t kid=kid if kid else \"Gkncy6f9BSp7wdav8w4SNZE1yt0\",\n42\t use=\"sig\",\n43\t kty=\"RSA\",\n44\t e=\"AQAB\",\n45\t n=\"sXiw5dOOl6DwAFKYQP623hUOs7T0f2mJEvMN1P-AkVbwagxanJzyRpJJX2zyXtIYnsTrlsjrSRzBTvWBZCXGW4XpmcSIKoRky_hBJGgK6shK\"\n46\t \"3375oThcAq01JZWEWXU2roYyBQz7VxvUSIAPmQVXn9TCQ7YT_TQOg39Dzot2PZPZtabKM2IQEtV6vVmciqz3QkMnclvGnUAca6KZCPBotdNX\"\n47\t \"9dWedAOBHmipCzzYIHutnMXsTZtPCEvrlgYyS1yD7u1WaxPgl84D6uglqDBF6WF1Vr2fgeeWfyujiJ_U26BCq6DmGQCN7BPAhJJso6bvP27G\"\n48\t \"58wZGR3HM_bjJ716Zw\",\n49\t x5c=[\n50\t \"MIIDbjCCAlagAwIBAgIUQ/BwWYGeDkDQjbUycWZqI/FeUDcwD", "truncated": true}]} +{"ts": 1778657756.5455644, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now let me look at the test fixtures for the organization to understand the cassette format, and also look at how the data source service handles this:", "truncated": false}]} +{"ts": 1778657757.4010956, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01AieC1B49iYUCLC1ZzvdEW1", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/*.yaml\"}", "truncated": false}]} +{"ts": 1778657757.8486648, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01AieC1B49iYUCLC1ZzvdEW1", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/fixtures/organization/create_csp_directive.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/create_jwk.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/create_organization_setting.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/delete_csp_directive.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/delete_jwk.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/delete_organization_setting.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/layout_notification_channels.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/list_csp_directives.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/list_jwk.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/list_organization_settings.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/organization.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/update_allowed_origins.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/update_csp_directive.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/update_jwk.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/update_name.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/update_organization_setting.yaml\npackages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml", "truncated": false}]} +{"ts": 1778657758.4498749, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01R7st7Eu2qGWngZ9sixHbrU", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 400, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657758.5041695, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01R7st7Eu2qGWngZ9sixHbrU", "is_error": false, "content": "400\t def create_identity_provider(self, identity_provider: CatalogIdentityProvider) -> None:\n401\t \"\"\"Create a new identity provider.\n402\t\n403\t Args:\n404\t identity_provider (CatalogIdentityProvider):\n405\t A catalog identity provider object to be created.\n406\t\n407\t Returns:\n408\t None\n409\t \"\"\"\n410\t identity_provider_document = JsonApiIdentityProviderInDocument(data=identity_provider.to_api())\n411\t self._entities_api.create_entity_identity_providers(\n412\t json_api_identity_provider_in_document=identity_provider_document\n413\t )\n414\t\n415\t def delete_identity_provider(self, identity_provider_id: str) -> None:\n416\t \"\"\"Delete an identity provider.\n417\t\n418\t Args:\n419\t identity_provider_id (str):\n420\t Identity provider identification string e.g. \"demo\"\n421\t\n422\t Returns:\n423\t None\n424\t \"\"\"\n425\t self._entities_api.delete_entity_identity_providers(identity_provider_id)\n426\t\n427\t def update_identity_provider(self, identity_provider: CatalogIdentityProvider) -> None:\n428\t \"\"\"Update an identity provider.\n429\t\n430\t Args:\n431\t identity_provider (CatalogIdentityProvider):\n432\t A catalog identity provider object to be updated.\n433\t\n434\t Returns:\n435\t None\n436\t\n437\t Raises:\n438\t ValueError:\n439\t Identity provider does not exist.\n440\t \"\"\"\n441\t try:\n442\t identity_provider_document = JsonApiIdentityProviderInDocument(data=identity_provider.to_api())\n443\t self._entities_api.update_entity_identity_providers(identity_provider.id, identity_provider_document)\n444\t except NotFoundException:\n445\t raise ValueError(\n446\t f\"Can not update {identity_provider.id} identity provider. This identity provider does not exist.\"\n447\t )\n448\t\n449\t def patch_identit", "truncated": true}]} +{"ts": 1778657760.7370214, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look at the existing cassette for the test to understand what it captures:", "truncated": false}]} +{"ts": 1778657761.5203195, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01JGyR8XddbXA6jW1meVQv7D", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} +{"ts": 1778657761.5555537, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JGyR8XddbXA6jW1meVQv7D", "is_error": true, "content": "File content (463.7KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.", "truncated": false}]} +{"ts": 1778657763.3975809, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01CNVLK1xQvZE3v3fReZ3AMX", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 1, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657763.429623, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CNVLK1xQvZE3v3fReZ3AMX", "is_error": false, "content": "1\tinteractions:\n2\t - request:\n3\t body: null\n4\t headers:\n5\t Accept:\n6\t - application/json\n7\t Accept-Encoding:\n8\t - br, gzip, deflate\n9\t X-GDC-VALIDATE-RELATIONS:\n10\t - 'true'\n11\t X-Requested-With:\n12\t - XMLHttpRequest\n13\t method: GET\n14\t uri: http://localhost:3000/api/v1/layout/organization\n15\t response:\n16\t body:\n17\t string:\n18\t agents:\n19\t - aiKnowledge: true\n20\t availableToAll: true\n21\t enabled: true\n22\t id: default-ai-assistant\n23\t name: Default GoodData AI Assistant\n24\t skillsMode: all\n25\t customGeoCollections: []\n26\t dataSources:\n27\t - alternativeDataSourceId: ds-put-abc-id\n28\t authenticationType: USERNAME_PASSWORD\n29\t id: demo-test-ds\n30\t name: demo-test-ds\n31\t permissions:\n32\t - assignee:\n33\t id: demo2\n34\t type: user\n35\t name: MANAGE\n36\t - assignee:\n37\t id: demoGroup\n38\t type: userGroup\n39\t name: USE\n40\t schema: demo\n41\t type: POSTGRESQL\n42\t url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\n43\t username: postgres\n44\t exportTemplates: []\n45\t identityProviders:\n46\t - id: defaultIdp\n47\t idpType: DEX_IDP\n48\t ipAllowlistPolicies: []\n49\t jwks: []\n50\t notificationChannels: []\n51\t organization:\n52\t allowedOrigins: []\n53\t colorPalettes: []\n54\t cspDirectives: []\n55\t earlyAccess: enableAlerting\n56\t earlyAccessValues:\n57\t - enableAlerting\n58\t - enableSmtp\n59\t - enablePreAggregationDatasets\n60\t - enableScheduling\n61\t - e", "truncated": true}]} +{"ts": 1778657766.6971674, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I can see the cassette has a data source with:\n- `authenticationType: USERNAME_PASSWORD`\n- `username: postgres`\n\nBut no `password` field. This is the problem. When we GET the org layout and then PUT it back, the server validates the data source and finds that it has a username but no password.\n\nLet me look at more of the cassette to understand the full structure and then look at the PUT request:", "truncated": false}]} +{"ts": 1778657768.3152275, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01XTyyjCEZaczvzx4xiRpeeV", "input": "{\"command\": \"grep -n \\\"PUT\\\\|post\\\\|password\\\\|authenticationType\\\\|username\\\\|demo-test-ds\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml | head -80\", \"description\": \"Find PUT requests and credential fields in the cassette\"}", "truncated": false}]} +{"ts": 1778657768.3755836, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XTyyjCEZaczvzx4xiRpeeV", "is_error": true, "content": "Blocked: grep -n \"PUT\\|post\\|password\\|authenticationType\\|username\\|demo-test-ds\" /home/", "truncated": false}]} +{"ts": 1778657771.013694, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_015198Zi93H73HoDSGNvb54P", "input": "{\"pattern\": \"PUT|password|authenticationType|username|demo-test-ds\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\", \"head_limit\": 80}", "truncated": false}]} +{"ts": 1778657771.094231, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015198Zi93H73HoDSGNvb54P", "is_error": false, "content": "28: authenticationType: USERNAME_PASSWORD\n29: id: demo-test-ds\n30: name: demo-test-ds\n43: username: postgres\n1694: dataSourceId: demo-test-ds\n1768: dataSourceId: demo-test-ds\n1795: dataSourceId: demo-test-ds\n1859: dataSourceId: demo-test-ds\n1905: dataSourceId: demo-test-ds\n2022: dataSourceId: demo-test-ds\n2173: authenticationType: USERNAME_PASSWORD\n2174: id: demo-test-ds\n2175: name: demo-test-ds\n2188: username: postgres\n3839: dataSourceId: demo-test-ds\n3913: dataSourceId: demo-test-ds\n3940: dataSourceId: demo-test-ds\n4004: dataSourceId: demo-test-ds\n4050: dataSourceId: demo-test-ds\n4167: dataSourceId: demo-test-ds\n4303: authenticationType: USERNAME_PASSWORD\n4304: id: demo-test-ds\n4305: name: demo-test-ds\n4318: username: postgres\n5978: dataSourceId: demo-test-ds\n6052: dataSourceId: demo-test-ds\n6079: dataSourceId: demo-test-ds\n6143: dataSourceId: demo-test-ds\n6189: dataSourceId: demo-test-ds\n6306: dataSourceId: demo-test-ds\n6425: method: PUT\n6430: detail: 'Invalid combination of auth properties. Only none, user + password,\n6431: token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n6432: user: , password: , token: , key-pair: , clientId: ,\n6477: authenticationType: USERNAME_PASSWORD\n6478: id: demo-test-ds\n6479: name: demo-test-ds\n6492: username: postgres\n8143: dataSourceId: d", "truncated": true}]} +{"ts": 1778657791.7224348, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The cassette has recorded PUT requests that result in 400 errors. The cassette was recorded with these failures - the test was expected to handle the 400 error, but it doesn't.\n\nLooking at line 6425: `method: PUT` with line 6430 showing the 400 error detail.\n\nSo the cassette itself contains the 400 error response. This means the test was run against a real server which returned a 400 error, and the cassette recorded it. When the test runs again with the cassette, it will replay the 400 error.\n\nThe problem is in the `put_declarative_ip_allowlist_policies` method - it does a GET of the org layout, then PUTs it back, but the data source in the org layout has `username: postgres` but no password. The server validates this and returns 400.\n\n\nThe fix would be to strip credential fields from data sources before PUTting the org layout back, or to clear the data source credentials entirely rather than sending partial credentials with an auth type that requires them.\n\nBut I'm realizing the cassette file already exists and contains the 400 error baked in. The instructions say not to fabricate cassettes since they'll be re-recorded by the pipeline, but this cassette wasn't deleted and has the failure recorded. So either I need to fix the service code to prevent the 400 error from happening in the first place, or the cassette needs to be updated to remove it. If the cassette replays the 400 error, the test will fail when the code tries to handle that response. The cassette has two PUT requests that both return 400 errors \u2014 one for the initial policy update and one for the restoration in the finally block. Looking at the test flow, it seems the cassette was recorded when the server was already rejecting these PUT requests, which is why the test is failing now.\n\nI need to examine what's actually in the PUT request body around line 6425 to understand what's causing the 400 error.", "truncated": false}]} +{"ts": 1778657791.7420647, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_019zPt6KseUAiQt7Xy4Vnigc", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6415, \"limit\": 70}", "truncated": false}]} +{"ts": 1778657791.7590632, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_019zPt6KseUAiQt7Xy4Vnigc", "is_error": false, "content": "6415\t userDataFilters: []\n6416\t headers:\n6417\t Accept-Encoding:\n6418\t - br, gzip, deflate\n6419\t Content-Type:\n6420\t - application/json\n6421\t X-GDC-VALIDATE-RELATIONS:\n6422\t - 'true'\n6423\t X-Requested-With:\n6424\t - XMLHttpRequest\n6425\t method: PUT\n6426\t uri: http://localhost:3000/api/v1/layout/organization\n6427\t response:\n6428\t body:\n6429\t string:\n6430\t detail: 'Invalid combination of auth properties. Only none, user + password,\n6431\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n6432\t user: , password: , token: , key-pair: , clientId: ,\n6433\t clientSecret: '\n6434\t status: 400\n6435\t title: Bad Request\n6436\t traceId: NORMALIZED_TRACE_ID_000000000000\n6437\t headers:\n6438\t Content-Type:\n6439\t - application/problem+json\n6440\t DATE: *id001\n6441\t Expires:\n6442\t - '0'\n6443\t Pragma:\n6444\t - no-cache\n6445\t X-Content-Type-Options:\n6446\t - nosniff\n6447\t X-GDC-TRACE-ID: *id001\n6448\t status:\n6449\t code: 400\n6450\t message: Bad Request\n6451\t - request:\n6452\t body: null\n6453\t headers:\n6454\t Accept:\n6455\t - application/json\n6456\t Accept-Encoding:\n6457\t - br, gzip, deflate\n6458\t X-GDC-VALIDATE-RELATIONS:\n6459\t - 'true'\n6460\t X-Requested-With:\n6461\t - XMLHttpRequest\n6462\t method: GET\n6463\t uri: http://localhost:3000/api/v1/layout/organization\n6464\t response:\n6465\t body:\n6466\t string:\n6467\t agents:\n6468\t - aiKnowledge: true\n6469\t availableToAll: true\n6470\t enabled: true\n6471\t id: default-ai-assistant\n6472\t name: Default GoodData AI Assistant\n6473\t skillsMode: all\n6474\t cu", "truncated": true}]} +{"ts": 1778657840.2344227, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the cassette captures:\n1. First GET of org layout \u2192 returned with data source that has `username: postgres` but no password\n2. First PUT (for new_policies) \u2192 400 error (because the data source has username but no password)\n3. Second GET (part of the teardown's `put_declarative_ip_allowlist_policies`)\n4. Second PUT (in finally block) \u2192 Also 400 error\n\nThe cassette has the 400 error BAKED IN. This is the problem - the cassette was recorded when the service had this bug.\n\nThe fix for the service would be to strip partial credentials from data sources before PUTting the org layout back. \n\nBut here's the catch: if we fix the service to not send the `username` field, the PUT request body changes, so the cassette won't match it anymore. We'd either get a mismatch error or VCR would use the next unmatched request depending on configuration. The real solution is to delete the cassette and re-record it with the fixed service.\n\nThe instructions say stale cassettes were already deleted, but this cassette still exists at the layout_ip_allowlist_policies.yaml path with the 400 error recorded in it. That seems contradictory\u2014either the cassette should have been deleted, or maybe it's supposed to be there for a reason. Let me reconsider what's actually happening here.\n\nThe cassette exists and contains the 400 error response, so when the test runs against it via VCR, it replays that failure and the test fails. The real issue is that the service code reads the full org layout and writes it back without the password field, which causes the 400 error. So I need to both fix the service code and delete the bad cassette so the pipeline can re-record it. But if the underlying data source in the org layout is missing the password, the real server might return the same 400 error when re-recording happens.\n\nThe root cause is that the data source has `authenticationType: USERNAME_PASSWORD` with a username but no password, which the server rejects as invalid. The fix is to handle this in the ", "truncated": true}]} +{"ts": 1778657840.277337, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how the notification channels method handles this and also check what's in the cassette around the PUT request body:", "truncated": false}]} +{"ts": 1778657840.5905392, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01WThxBaVkZSkmpvVcJwv3Uh", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6200, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657841.0213256, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01WThxBaVkZSkmpvVcJwv3Uh", "is_error": false, "content": "6200\t sourceColumn: price\n6201\t sourceColumnDataType: NUMERIC\n6202\t tags:\n6203\t - Order lines\n6204\t title: Price\n6205\t - description: Quantity\n6206\t id: quantity\n6207\t isNullable: true\n6208\t sourceColumn: quantity\n6209\t sourceColumnDataType: NUMERIC\n6210\t tags:\n6211\t - Order lines\n6212\t title: Quantity\n6213\t grain:\n6214\t - id: order_line_id\n6215\t type: attribute\n6216\t id: order_lines\n6217\t references:\n6218\t - identifier:\n6219\t id: campaigns\n6220\t type: dataset\n6221\t multivalue: false\n6222\t sources:\n6223\t - column: campaign_id\n6224\t dataType: INT\n6225\t isNullable: true\n6226\t target:\n6227\t id: campaign_id\n6228\t type: attribute\n6229\t - identifier:\n6230\t id: customers\n6231\t type: dataset\n6232\t multivalue: false\n6233\t sources:\n6234\t - column: customer_id\n6235\t dataType: INT\n6236\t isNullable: true\n6237\t target:\n6238\t id: customer_id\n6239\t type: attribute\n6240\t - identifier:\n6241\t id: date\n6242\t type: dataset\n6243\t multivalue: false\n62", "truncated": true}]} +{"ts": 1778657841.3705266, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_0127DK74yLG5UZuiaTbrdMCp", "input": "{\"pattern\": \"def put_declarative_notification_channels\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778657841.410275, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0127DK74yLG5UZuiaTbrdMCp", "is_error": false, "content": "647: def put_declarative_notification_channels(", "truncated": false}]} +{"ts": 1778657843.7097712, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01W6h5szKFVWjGRbozToZ43L", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 647, \"limit\": 80}", "truncated": false}]} +{"ts": 1778657843.7434337, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01W6h5szKFVWjGRbozToZ43L", "is_error": false, "content": "647\t def put_declarative_notification_channels(\n648\t self, notification_channels: list[CatalogDeclarativeNotificationChannel]\n649\t ) -> None:\n650\t \"\"\"\n651\t Put declarative notification channels in the current organization.\n652\t\n653\t Args:\n654\t notification_channels (list[CatalogDeclarativeNotificationChannel]):\n655\t List of declarative notification channels.\n656\t\n657\t Returns:\n658\t None\n659\t \"\"\"\n660\t api_ncs = [nc.to_api() for nc in notification_channels]\n661\t self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n662\t\n663\t def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:\n664\t \"\"\"\n665\t Get all declarative identity providers in the current organization.\n666\t\n667\t Returns:\n668\t list[CatalogDeclarativeIdentityProvider]:\n669\t List of declarative identity providers.\n670\t \"\"\"\n671\t return [\n672\t CatalogDeclarativeIdentityProvider.from_api(idp) for idp in self._layout_api.get_identity_providers_layout()\n673\t ]\n674\t\n675\t def put_declarative_identity_providers(self, identity_providers: list[CatalogDeclarativeIdentityProvider]) -> None:\n676\t \"\"\"\n677\t Put declarative identity providers in the current organization.\n678\t\n679\t Args:\n680\t identity_providers (list[CatalogDeclarativeIdentityProvider]):\n681\t List of declarative identity providers.\n682\t\n683\t Returns:\n684\t None\n685\t \"\"\"\n686\t api_idps = [idp.to_api() for idp in identity_providers]\n687\t self._layout_api.set_identity_providers(declarative_identity_provider=api_idps)\n688\t\n689\t def get_declarative_export_templates(self) -> list[CatalogDeclarativeExportTemplate]:\n690\t \"\"\"\n691\t Get all declarative export templates in the current organization.\n692\t\n693\t ", "truncated": true}]} +{"ts": 1778657850.3061254, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see the pattern! The `put_declarative_notification_channels` and `put_declarative_identity_providers` methods use **dedicated APIs**:\n- `self._layout_api.set_notification_channels(...)` for notification channels\n- `self._layout_api.set_identity_providers(...)` for identity providers\n- `self._layout_api.set_export_templates(...)` for export templates\n\nBut the `put_declarative_ip_allowlist_policies` method uses the full org layout:\n\n\nFetching the entire organization layout, updating just the IP allowlist policies field, then writing it back. This is the inconsistency\u2014there's no dedicated API for IP allowlist policies, so it's falling back to the full layout approach. Let me check if a dedicated API exists for this.", "truncated": false}]} +{"ts": 1778657850.3066306, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the layout API for dedicated IP allowlist endpoints:", "truncated": false}]} +{"ts": 1778657850.734343, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Jwc2TJC7d4wZd17ohZX6He", "input": "{\"pattern\": \"ip_allowlist\\\\|IpAllowlist\\\\|allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778657850.7744575, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Jwc2TJC7d4wZd17ohZX6He", "is_error": true, "content": "Path does not exist: /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client/gooddata_api_client/api/layout_api.py. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} +{"ts": 1778657852.6123154, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_011KzeT2X88itJaj8VhU4xAA", "input": "{\"command\": \"find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \\\"layout_api.py\\\" 2>/dev/null | head -5\", \"description\": \"Find layout_api.py location\"}", "truncated": false}]} +{"ts": 1778657852.6764345, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011KzeT2X88itJaj8VhU4xAA", "is_error": true, "content": "Blocked: find /home/runner/_work/gdc-nas/gdc-nas/sdk -name \"layout_api.py\" 2>/dev/null | ", "truncated": false}]} +{"ts": 1778657854.0668855, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_016eCbFrheFRKLftVMQX1HJ7", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/**/layout_api.py\"}", "truncated": false}]} +{"ts": 1778657854.098902, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016eCbFrheFRKLftVMQX1HJ7", "is_error": false, "content": "gooddata-api-client/build/lib/gooddata_api_client/api/layout_api.py\ngooddata-api-client/gooddata_api_client/api/layout_api.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/gooddata_api_client/api/layout_api.py", "truncated": false}]} +{"ts": 1778657856.6146915, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_015H9WSanwy3zcS914hCGJNc", "input": "{\"pattern\": \"ip_allowlist\\\\|IpAllowlist\\\\|allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778657856.9475136, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015H9WSanwy3zcS914hCGJNc", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778657878.7492108, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no dedicated IP allowlist API in the layout_api. So the prior agent's approach of using the full org layout is the only option.\n\nThe problem is that the `put_declarative_ip_allowlist_policies` method reads the full org layout and PUTs it back. The full org layout includes data sources with partial credentials, which causes a 400 error.\n\nThe fix needs to handle this. Let me think about options:\n\n1. **Strip data source credentials before PUT**: When the data source has a username but no password (or partial credentials), clear those credentials before PUTting.\n\n\n2. **Handle the validation issue differently**: The error shows that data sources with a username but no password violate the allowed auth combinations. The valid options are none, user + password, token, key-pair, or clientId + clientSecret. So when I encounter a data source with incomplete credentials like just a username, I need to either remove all credentials or ensure they're in a valid combination.\n\nBut clearing the username would lose data when the org layout is written back. The real issue is that the test reads the entire org layout, modifies it, and writes it back\u2014but passwords aren't returned in GET responses, so credentials can't be fully round-tripped. This is a fundamental design problem with using the full org layout for IP allowlist policies, whereas notification channels and identity providers have dedicated APIs that avoid this. The cleanest solution is to handle this in the declarative IP allowlist function itself.\n\nImplementing a helper method to strip partial data source credentials before the PUT request... I need to verify the exact attribute names the API client uses\u2014the JSON response shows camelCase keys like `authenticationType` and `username`, but the Python client likely converts these to snake_case attributes like `authentication_type`. Let me check the data source model to confirm the field mappings.", "truncated": false}]} +{"ts": 1778657878.788093, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the data source API model to understand the field names:", "truncated": false}]} +{"ts": 1778657878.8533247, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Bn823Kj6BMNt9p47fDsuF5", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source*.py\"}", "truncated": false}]} +{"ts": 1778657878.9086435, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Bn823Kj6BMNt9p47fDsuF5", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\ngooddata-api-client/gooddata_api_client/model/declarative_data_source_permission.py\ngooddata-api-client/gooddata_api_client/model/declarative_data_source_permissions.py\ngooddata-api-client/gooddata_api_client/model/declarative_data_sources.py", "truncated": false}]} +{"ts": 1778657880.7297103, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01Jetxi4ZzELPftjvoUafFH7", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 1, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657880.7662528, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Jetxi4ZzELPftjvoUafFH7", "is_error": false, "content": "1\t\"\"\"\n2\t OpenAPI definition\n3\t\n4\t No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501\n5\t\n6\t The version of the OpenAPI document: v0\n7\t Contact: support@gooddata.com\n8\t Generated by: https://openapi-generator.tech\n9\t\"\"\"\n10\t\n11\t\n12\timport re # noqa: F401\n13\timport sys # noqa: F401\n14\t\n15\tfrom gooddata_api_client.model_utils import ( # noqa: F401\n16\t ApiTypeError,\n17\t ModelComposed,\n18\t ModelNormal,\n19\t ModelSimple,\n20\t cached_property,\n21\t change_keys_js_to_python,\n22\t convert_js_args_to_python_args,\n23\t date,\n24\t datetime,\n25\t file_type,\n26\t none_type,\n27\t validate_get_composed_info,\n28\t OpenApiModel\n29\t)\n30\tfrom gooddata_api_client.exceptions import ApiAttributeError\n31\t\n32\t\n33\tdef lazy_import():\n34\t from gooddata_api_client.model.declarative_data_source_permission import DeclarativeDataSourcePermission\n35\t from gooddata_api_client.model.parameter import Parameter\n36\t globals()['DeclarativeDataSourcePermission'] = DeclarativeDataSourcePermission\n37\t globals()['Parameter'] = Parameter\n38\t\n39\t\n40\tclass DeclarativeDataSource(ModelNormal):\n41\t \"\"\"NOTE: This class is auto generated by OpenAPI Generator.\n42\t Ref: https://openapi-generator.tech\n43\t\n44\t Do not edit the class manually.\n45\t\n46\t Attributes:\n47\t allowed_values (dict): The key is the tuple path to the attribute\n48\t and the for var_name this is (var_name,). The value is a dict\n49\t with a capitalized key describing the allowed value and an allowed\n50\t value. These dicts store the allowed enum values.\n51\t attribute_map (dict): The key is attribute name\n52\t and the value is json key in definition.\n53\t discriminator_value_class_map (dict): A dict to go from the discriminator\n54\t variable value to the discriminator class name.\n55\t validations (dict): The key is the tuple path to the attribute\n56\t a", "truncated": true}]} +{"ts": 1778657883.180254, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_014HKWiMqoqtYLmUSgocvxzZ", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_data_source.py\", \"offset\": 100, \"limit\": 100}", "truncated": false}]} +{"ts": 1778657883.2163785, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014HKWiMqoqtYLmUSgocvxzZ", "is_error": false, "content": "100\t 'CLIENT_SECRET': \"CLIENT_SECRET\",\n101\t 'ACCESS_TOKEN': \"ACCESS_TOKEN\",\n102\t },\n103\t ('cache_strategy',): {\n104\t 'ALWAYS': \"ALWAYS\",\n105\t 'NEVER': \"NEVER\",\n106\t },\n107\t ('date_time_semantics',): {\n108\t 'None': None,\n109\t 'LOCAL': \"LOCAL\",\n110\t 'UTC': \"UTC\",\n111\t },\n112\t }\n113\t\n114\t validations = {\n115\t ('id',): {\n116\t 'regex': {\n117\t 'pattern': r'^(?!\\.)[.A-Za-z0-9_-]{1,255}$', # noqa: E501\n118\t },\n119\t },\n120\t ('name',): {\n121\t 'max_length': 255,\n122\t },\n123\t ('schema',): {\n124\t 'max_length': 255,\n125\t },\n126\t ('alternative_data_source_id',): {\n127\t 'regex': {\n128\t 'pattern': r'^(?!\\.)[.A-Za-z0-9_-]{1,255}$', # noqa: E501\n129\t },\n130\t },\n131\t ('client_id',): {\n132\t 'max_length': 255,\n133\t },\n134\t ('client_secret',): {\n135\t 'max_length': 255,\n136\t },\n137\t ('password',): {\n138\t 'max_length': 255,\n139\t },\n140\t ('private_key',): {\n141\t 'max_length': 15000,\n142\t },\n143\t ('private_key_passphrase',): {\n144\t 'max_length': 255,\n145\t },\n146\t ('token',): {\n147\t 'max_length': 10000,\n148\t },\n149\t ('url',): {\n150\t 'max_length': 255,\n151\t },\n152\t ('username',): {\n153\t 'max_length': 255,\n154\t },\n155\t }\n156\t\n157\t @cached_property\n158\t def additional_properties_type():\n159\t \"\"\"\n160\t This must be a method because a model may have properties that are\n161\t of type self, this must run after the class is loaded\n162\t \"\"\"\n163\t lazy_import()\n164\t return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501\n165\t\n166\t _nullable = False\n167\t\n168\t ", "truncated": true}]} +{"ts": 1778657900.0442698, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the data source model structure. The data source has:\n- `authentication_type` (optional)\n- `username` (optional)\n- `password` (optional)\n- `token` (optional)\n- etc.\n\nWhen the GET returns a data source with `authentication_type: USERNAME_PASSWORD` and `username: postgres` but no `password`, putting this back will fail because the server requires username+password for `USERNAME_PASSWORD` auth.\n\nNow, the fix approach:\n1. In `put_declarative_ip_allowlist_policies`, before PUTting the org layout, clear the `username` from any data source that has `authentication_type: USERNAME_PASSWORD` but no `password`.\n\n\n2. The real issue is that the cassette is replaying the 400 error from the failed request, so I need to delete it and let it get re-recorded with the corrected data. The instructions claim the cassette was already deleted, but it still exists with bad data in it. I need to figure out whether the cassette should have been deleted or if there's something else going on\u2014let me look more closely at what the second PUT request in the cassette is actually doing.", "truncated": false}]} +{"ts": 1778657900.0537574, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the second PUT in the cassette:", "truncated": false}]} +{"ts": 1778657900.4519372, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01GdAqgz7pjLMDi6VFq7nkNY", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 10700, \"limit\": 50}", "truncated": false}]} +{"ts": 1778657900.4897232, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GdAqgz7pjLMDi6VFq7nkNY", "is_error": false, "content": "10700\t ldm:\n10701\t datasets: []\n10702\t dateInstances: []\n10703\t name: Demo West California\n10704\t parent:\n10705\t id: demo_west\n10706\t type: workspace\n10707\t permissions: []\n10708\t settings: []\n10709\t userDataFilters: []\n10710\t headers:\n10711\t Accept-Encoding:\n10712\t - br, gzip, deflate\n10713\t Content-Type:\n10714\t - application/json\n10715\t X-GDC-VALIDATE-RELATIONS:\n10716\t - 'true'\n10717\t X-Requested-With:\n10718\t - XMLHttpRequest\n10719\t method: PUT\n10720\t uri: http://localhost:3000/api/v1/layout/organization\n10721\t response:\n10722\t body:\n10723\t string:\n10724\t detail: 'Invalid combination of auth properties. Only none, user + password,\n10725\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n10726\t user: , password: , token: , key-pair: , clientId: ,\n10727\t clientSecret: '\n10728\t status: 400\n10729\t title: Bad Request\n10730\t traceId: NORMALIZED_TRACE_ID_000000000000\n10731\t headers:\n10732\t Content-Type:\n10733\t - application/problem+json\n10734\t DATE: *id001\n10735\t Expires:\n10736\t - '0'\n10737\t Pragma:\n10738\t - no-cache\n10739\t X-Content-Type-Options:\n10740\t - nosniff\n10741\t X-GDC-TRACE-ID: *id001\n10742\t status:\n10743\t code: 400\n10744\t message: Bad Request\n10745\tversion: 1\n10746\t", "truncated": false}]} +{"ts": 1778657910.8223526, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK so the cassette has two PUT requests, both returning 400. The cassette was recorded when the bug was present.\n\nNow I need to understand: is this cassette supposed to be used in playback mode, or does it need to be re-recorded?\n\nThe problem statement says the test FAILS. The cassette records the failure. So to fix the test, I need to:\n1. Fix the service code \n2. Delete the cassette (so it gets re-recorded with the fixed code)\n\nBut if I delete the cassette, the test will run against the real staging server. \n\nSo my strategy is to fix `put_declarative_ip_allowlist_policies` to handle incomplete credentials gracefully\u2014specifically, when a data source has a username but no password, I'll clear the username to prevent validation errors. Same logic applies for token-based auth. Then I'll delete the bad cassette so it gets re-recorded with the corrected behavior.\n\nBut wait, I should check if there's actually a dedicated IP allowlist API endpoint rather than relying on the full org layout like I'm doing now.", "truncated": false}]} +{"ts": 1778657910.8414037, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at all available layout API methods to check if there's a dedicated IP allowlist endpoint:", "truncated": false}]} +{"ts": 1778657912.5031137, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_017LyDMFEumfqJ6jQnYSWQuM", "input": "{\"pattern\": \"def (get|set|put|post).*ip|def (get|set|put|post).*allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 30, \"-i\": true}", "truncated": false}]} +{"ts": 1778657912.972119, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017LyDMFEumfqJ6jQnYSWQuM", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778657913.3084219, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_014sa7RMid7NxsJBHmQD54cw", "input": "{\"pattern\": \"def [a-z]\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 100}", "truncated": false}]} +{"ts": 1778657913.4933436, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014sa7RMid7NxsJBHmQD54cw", "is_error": false, "content": "2495: def delete_data_source_statistics(\n2578: def get_agents_layout(\n2656: def get_analytics_model(\n2740: def get_automations(\n2824: def get_custom_geo_collections_layout(\n2902: def get_data_source_permissions(\n2985: def get_data_source_statistics(\n3070: def get_data_sources_layout(\n3148: def get_export_templates_layout(\n3226: def get_filter_views(\n3310: def get_identity_providers_layout(\n3388: def get_logical_model(\n3472: def get_notification_channels_layout(\n3550: def get_organization_layout(\n3629: def get_organization_permissions(\n3707: def get_user_data_filters(\n3790: def get_user_group_permissions(\n3873: def get_user_groups_layout(\n3951: def get_user_permissions(\n4034: def get_users_layout(\n4112: def get_users_user_groups_layout(\n4190: def get_workspace_data_filters_layout(\n4268: def get_workspace_layout(\n4352: def get_workspace_permissions(\n4435: def get_workspaces_layout(\n4514: def put_data_source_statistics(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5103: def set_analytics_model(\n5190: def set_automations(\n5277: def set_custom_geo_collections(\n5360: def set_data_source_permissions(\n5447: def set_export_templates(\n5530: def set_filter_views(\n5617: def set_identity_providers(\n5700: def set_logical_model(\n5787: def set_notification_channels(\n5870: def set_organization_layout(\n5953: def set_organization_permissions(\n6036: def set_user_data_filters(\n6123: def set_user_group_permissions(\n6210: def set_user_permissions(\n6297: def set_workspace_data_filters_layout(\n6380: def set_workspace_permissions(\n6467: def set_workspaces_layout(", "truncated": false}]} +{"ts": 1778657928.2554069, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no dedicated `set_ip_allowlist_policies` or similar method in the layout API. So the prior agent had to use `set_organization_layout`, which requires the full org layout. The issue is that the full org layout includes data sources with partial credentials.\n\nNow let me think about the fix:\n\nThe `put_declarative_ip_allowlist_policies` method needs to handle data sources with partial credentials. The cleanest fix would be to clear all credential fields from data sources before PUTting.\n\n\nLooking at the data source model, I need to strip out all the credential fields\u2014username, password, token, client_id, client_secret, private_key, and private_key_passphrase\u2014since the server returns them partially populated when we GET the org layout, which causes the PUT to fail. Clearing these fields entirely will let the IP allowlist update go through without authentication conflicts.\n\nBut wait, that would permanently wipe the data source credentials, which isn't acceptable. The real issue is that we're using a full org layout API when we only need to update the IP allowlist policy\u2014notification channels avoid this problem by having a dedicated endpoint. Since there's no dedicated API for IP allowlist policies, I'm stuck using the full org layout call, but I need to find a way to update the policy without corrupting the data source auth configuration.\n\nMaybe I should change the authentication type to `None` and clear the username before the PUT, then restore it afterward\u2014or check if there's another approach that doesn't require modifying the data source at all.", "truncated": false}]} +{"ts": 1778657928.2561488, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check how the data source layout PUT handles credentials:", "truncated": false}]} +{"ts": 1778657929.4480197, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01TEJfnPvisb3gPQppUHTSts", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/data_source/declarative_model/data_source.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} +{"ts": 1778657929.4817834, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TEJfnPvisb3gPQppUHTSts", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\tfrom pathlib import Path\n6\tfrom typing import Any, Union\n7\tfrom warnings import warn\n8\t\n9\tfrom attrs import define, field\n10\tfrom gooddata_api_client.model.declarative_data_source import DeclarativeDataSource\n11\tfrom gooddata_api_client.model.declarative_data_sources import DeclarativeDataSources\n12\tfrom gooddata_api_client.model.test_definition_request import TestDefinitionRequest\n13\t\n14\tfrom gooddata_sdk.catalog.base import Base, value_in_allowed\n15\tfrom gooddata_sdk.catalog.entity import ClientSecretCredentialsFromFile, TokenCredentialsFromFile\n16\tfrom gooddata_sdk.catalog.parameter import CatalogParameter\n17\tfrom gooddata_sdk.catalog.permission.declarative_model.permission import CatalogDeclarativeDataSourcePermission\n18\tfrom gooddata_sdk.utils import create_directory, get_ds_credentials, read_layout_from_file, write_layout_to_file\n19\t\n20\tBIGQUERY_TYPE = \"BIGQUERY\"\n21\tDATABRICKS_TYPE = \"DATABRICKS\"\n22\tSNOWFLAKE_TYPE = \"SNOWFLAKE\"\n23\tPRIVATE_KEY = \"private_key\"\n24\tPRIVATE_KEY_PASSPHRASE = \"private_key_passphrase\"\n25\tLAYOUT_DATA_SOURCES_DIR = \"data_sources\"\n26\t\n27\t\n28\t@define(kw_only=True)\n29\tclass CatalogDeclarativeDataSources(Base):\n30\t data_sources: list[CatalogDeclarativeDataSource]\n31\t\n32\t def _inject_base(self, credentials: dict[str, Any]) -> DeclarativeDataSources:\n33\t data_sources = []\n34\t client_class = self.client_class()\n35\t for data_source in self.data_sources:\n36\t data_source_credentials = credentials.get(data_source.id)\n37\t if data_source_credentials is None:\n38\t data_sources.append(data_source.to_api())\n39\t else:\n40\t if data_source.type == BIGQUERY_TYPE:\n41\t token = TokenCredentialsFromFile.token_from_file(data_source_credentials)\n42\t data_sources.append(data_source.to_api(token=token))\n43\t elif data_source.type == D", "truncated": true}]} +{"ts": 1778657932.5852613, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK, so the data source model handles credentials separately. The issue is specifically about the `put_declarative_ip_allowlist_policies` using `set_organization_layout`, which includes data sources.\n\nLet me look at the body of the PUT request in the cassette to understand what's being sent:", "truncated": false}]} +{"ts": 1778657932.9054344, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at what's in the PUT request body in the cassette to understand what's being sent:", "truncated": false}]} +{"ts": 1778657934.008978, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01MU57tkhJLqjKAUK9WRt7Cu", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 4280, \"limit\": 60}", "truncated": false}]} +{"ts": 1778657934.0615108, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MU57tkhJLqjKAUK9WRt7Cu", "is_error": false, "content": "4280\t DATE: *id001\n4281\t Expires:\n4282\t - '0'\n4283\t Pragma:\n4284\t - no-cache\n4285\t X-Content-Type-Options:\n4286\t - nosniff\n4287\t X-GDC-TRACE-ID: *id001\n4288\t status:\n4289\t code: 200\n4290\t message: OK\n4291\t - request:\n4292\t body:\n4293\t agents:\n4294\t - aiKnowledge: true\n4295\t availableToAll: true\n4296\t enabled: true\n4297\t id: default-ai-assistant\n4298\t name: Default GoodData AI Assistant\n4299\t skillsMode: all\n4300\t customGeoCollections: []\n4301\t dataSources:\n4302\t - alternativeDataSourceId: ds-put-abc-id\n4303\t authenticationType: USERNAME_PASSWORD\n4304\t id: demo-test-ds\n4305\t name: demo-test-ds\n4306\t permissions:\n4307\t - assignee:\n4308\t id: demo2\n4309\t type: user\n4310\t name: MANAGE\n4311\t - assignee:\n4312\t id: demoGroup\n4313\t type: userGroup\n4314\t name: USE\n4315\t schema: demo\n4316\t type: POSTGRESQL\n4317\t url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\n4318\t username: postgres\n4319\t exportTemplates: []\n4320\t identityProviders:\n4321\t - id: defaultIdp\n4322\t idpType: DEX_IDP\n4323\t ipAllowlistPolicies:\n4324\t - allowedSources:\n4325\t - 203.0.113.10/32\n4326\t - 198.51.100.0/24\n4327\t id: admin-vpn-only\n4328\t userGroups:\n4329\t - id: adminGroup\n4330\t type: userGroup\n4331\t users:\n4332\t - id: demo\n4333\t type: user\n4334\t jwks: []\n4335\t notificationChannels: []\n4336\t organization:\n4337\t allowedOrigins: []\n4338\t colorPalettes: []\n4339\t cspDirectives: []", "truncated": false}]} +{"ts": 1778657954.4674172, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I can see clearly what's in the PUT request body:\n\n```yaml\ndataSources:\n - alternativeDataSourceId: ds-put-abc-id\n authenticationType: USERNAME_PASSWORD\n id: demo-test-ds\n name: demo-test-ds\n ...\n username: postgres\n```\n\nThe `authenticationType: USERNAME_PASSWORD` and `username: postgres` is present without a `password`. The server rejects this.\n\nThe fix in the service is to clear the `username` (and set `authenticationType` to None) when there's no `password` for a `USERNAME_PASSWORD` auth type data source.\n\n\nI need to decide between fixing the service code and re-recording the cassette versus modifying the cassette directly, and the right approach is to fix the service and delete the cassette so it gets re-recorded. For the actual fix, I need to modify `put_declarative_ip_allowlist_policies` to strip out credentials from data sources before sending the PUT request.\n\nLooking at what's in the cassette, the PUT body includes authentication details like username and password. The most robust solution is to clear all credential fields (username, password, token, etc.) and set the authentication type to None for each data source in the org layout\u2014this way the server receives a data source with no authentication configured, which should be accepted.\n\nBut there's a catch: this approach would permanently change the data source's authentication settings on the server after the IP allowlist update completes. The real issue is that `set_organization_layout` is an all-or-nothing operation that touches every aspect of the organization, including data sources, so there's no way to update just the IP allowlist policies in isolation.\n\nLet me reconsider this differently\u2014what if we simply omit the credential fields from the data sources in the request and rely on the server to leave those fields unchanged? The key question is whether the API is designed to understand that missing credential fields means \"don't modify these,\" or if it interprets them as \"clear the", "truncated": true}]} +{"ts": 1778657954.4691813, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check if there's a dedicated IP allowlist API endpoint or model:", "truncated": false}]} +{"ts": 1778657954.4848812, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_017oskxfkXcJW58jrZmb36Jt", "input": "{\"pattern\": \"ip_allowlist\\\\|IpAllowlist\\\\|ipAllowlist\\\\|allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client\", \"output_mode\": \"content\", \"head_limit\": 50, \"-i\": true}", "truncated": false}]} +{"ts": 1778657954.5137534, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017oskxfkXcJW58jrZmb36Jt", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778657956.568534, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01LtqK5J6N9PTEz16RbdMALi", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/*allowlist*\"}", "truncated": false}]} +{"ts": 1778657956.581887, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LtqK5J6N9PTEz16RbdMALi", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py", "truncated": false}]} +{"ts": 1778657956.8620856, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_018YNMu9UMG5hoH18DBV9KWB", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/*ip_allow*\"}", "truncated": false}]} +{"ts": 1778657956.906059, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018YNMu9UMG5hoH18DBV9KWB", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py", "truncated": false}]} +{"ts": 1778657960.2904315, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_016595xLkzkh5dzJQ8iLrHnZ", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/*allowlist_policies*\"}", "truncated": false}]} +{"ts": 1778657960.3217595, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_016595xLkzkh5dzJQ8iLrHnZ", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778657976.0328674, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no `DeclarativeIpAllowlistPolicies` model (like there is `DeclarativeNotificationChannels` for notification channels). And there's no dedicated `set_ip_allowlist_policies` in the layout API.\n\nSo the only option is to use `set_organization_layout`. But we need to handle the data source credentials issue.\n\nNow, let me think about a different approach. What if we create a wrapper model like `DeclarativeIpAllowlistPolicies` manually and use `set_organization_layout` differently?\n\nActually, the real issue is that we're using `_check_return_type=False` to get the full org layout and then PUTting it back. \n\nWhen I fetch the org layout with `_check_return_type=False`, it returns the raw JSON response as a dict, which means data sources include their credentials. I could manipulate this dict directly to strip out sensitive fields before updating the layout back.\n\nLooking at the available credential fields in the data source model, I need to clear the appropriate ones based on the authentication type\u2014for username/password auth, I'd remove the username when the password isn't set.\n\nBut clearing all credentials would be a risky side effect that permanently modifies data sources during policy updates. The real issue is that when the test runs against the cassette, the request body needs to match what's recorded, so if I fix the service to not send the username, the cassette entry won't match anymore and the test will fail unless I regenerate it.\n\nLet me look at how VCR is configured in this project to understand the matching behavior better.", "truncated": false}]} +{"ts": 1778657976.0330205, "type": "assistant", "blocks": [{"type": "text", "text": "Let me check the VCR configuration used in tests:", "truncated": false}]} +{"ts": 1778657977.2148771, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01R2USTzhRSs9TeMxsUQNfa5", "input": "{\"pattern\": \"def get_vcr|match_on|record_mode\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} +{"ts": 1778657977.5498319, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01R2USTzhRSs9TeMxsUQNfa5", "is_error": false, "content": "packages/gooddata-sdk/tests/overview.md:62:gd_vcr = vcr.VCR(filter_headers=[\"authorization\", \"user-agent\"], serializer=\"json\", match_on=VCR_MATCH_ON)", "truncated": false}]} +{"ts": 1778657977.5500436, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01Tp46cqT43e6mw9UxpAJALE", "input": "{\"pattern\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/**/vcrpy_utils.py\"}", "truncated": false}]} +{"ts": 1778657977.585121, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Tp46cqT43e6mw9UxpAJALE", "is_error": false, "content": "packages/tests-support/src/tests_support/vcrpy_utils.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/tests_support/vcrpy_utils.py", "truncated": false}]} +{"ts": 1778657979.3661816, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_014c6W2eLRfAPkymrkwFsa7w", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\"}", "truncated": false}]} +{"ts": 1778657979.5560007, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014c6W2eLRfAPkymrkwFsa7w", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} +{"ts": 1778658022.467154, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand! The key insight is in the `_ENV_SPECIFIC_BODY_FIELDS` set and the `_body_matcher` function:\n\n```python\n_ENV_SPECIFIC_BODY_FIELDS = {\n \"password\",\n \"token\",\n \"url\",\n \"username\",\n \"privateKey\",\n \"client_secret\",\n \"private_key_passphrase\",\n}\n```\n\nAnd the `_body_matcher`:\n```python\ndef _body_matcher(r1: Any, r2: Any) -> None:\n \"\"\"Custom VCR body matcher that ignores environment-specific fields.\"\"\"\n\n\n```\n\nThe body matcher normalizes both request bodies by stripping out sensitive fields like username and password before comparing them. So even if the service sends different credentials in the PUT request, the normalized bodies would match the cassette. But here's the problem\u2014the cassette is still recording that 400 error response, so even if the request bodies align after normalization, we're still replaying the failed response.\n\nThe real issue is that the cassette itself contains the bad response. Fixing just the service code won't help because VCR will still match the normalized request to the cassette entry and return that 400 error. We need to delete the cassette and let it regenerate with the corrected service behavior.\n\nOnce we fix the service to properly handle credentials before the PUT request and delete the cassette, it'll be re-recorded with the successful response. Then the test will pass with the new cassette in place.\n\nNow I need to figure out the exact fix for the service code.\n\nOption 1 seems most robust\u2014clearing all credential fields from data sources before sending the PUT request. This prevents sending partial credentials that would cause the server to reject the request. If we clear the `authenticationType` to None along with the username and password fields, the PUT should succeed without trying to update the data source's authentication.\n\nBut I'm realizing there's a potential issue: if we change `authenticationType` to None, we're actually modifying the data source's auth configuration, which is a side effect", "truncated": true}]} +{"ts": 1778658022.474538, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at how the org layout object is structured when returned with `_check_return_type=False`:", "truncated": false}]} +{"ts": 1778658023.2992053, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01MDHEo8rVuxgyb1hcCL6gfH", "input": "{\"pattern\": \"data_sources|dataSources\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model/declarative_organization.py\", \"output_mode\": \"content\", \"head_limit\": 50}", "truncated": false}]} +{"ts": 1778658023.6827464, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01MDHEo8rVuxgyb1hcCL6gfH", "is_error": false, "content": "118: 'data_sources': ([DeclarativeDataSource],), # noqa: E501\n139: 'data_sources': 'dataSources', # noqa: E501\n197: data_sources ([DeclarativeDataSource]): [optional] # noqa: E501\n298: data_sources ([DeclarativeDataSource]): [optional] # noqa: E501", "truncated": false}]} +{"ts": 1778658052.7359948, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK, so `data_sources` (snake_case Python attribute) maps to `dataSources` (JSON key). And the data source model has:\n\n- `authentication_type` \u2192 `authenticationType`\n- `username` \u2192 `username`\n\nNow let me think about the fix. When using `_check_return_type=False`, the API returns a raw object. I need to check how to access and modify data source credential fields.\n\nActually, looking at the code pattern:\n\n\nWhen `_check_return_type=False` is used, the API returns a dict with camelCase keys matching the JSON response, so I'd need to use camelCase keys directly when accessing or modifying attributes on that returned object. I need to figure out what type of object `org_layout` is when `_check_return_type=False` is used, since the code assigns attributes to it directly like `org_layout.ip_allowlist_policies = [...]`, which wouldn't work if it were a dict. The API client must be deserializing the response into some kind of object that supports attribute assignment.\n\nSo I can access the data sources through `org_layout.data_sources`, where each one is a `DeclarativeDataSource` object with properties like `authentication_type`, `username`, and `password`. My approach is to iterate through these data sources before making the PUT request and strip out any partial credentials\u2014specifically when `authentication_type` is `\"USERNAME_PASSWORD\"` but only `username` is set without a `password`.\n\nWriting the implementation... I'm iterating through each data source and checking if it has a username without a password in USERNAME_PASSWORD auth mode\u2014if so, I'm clearing both the username and authentication type to avoid validation errors on the PUT request. But I'm realizing I need to verify that setting authentication_type to None is actually allowed by the model schema, so I'm checking what values are permitted. I'm trying to figure out the best way to handle clearing credentials from data sources when setting the organization layout. Since `_check_return_type=False` makes the model more", "truncated": true}]} +{"ts": 1778658052.739875, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the API client model_utils to understand what `_check_return_type=False` returns:", "truncated": false}]} +{"ts": 1778658052.7595937, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01Hof4XSaYHCYrsZbcp63Re4", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api_client.py\", \"description\": \"Check size of api_client.py\"}", "truncated": false}]} +{"ts": 1778658052.7900693, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Hof4XSaYHCYrsZbcp63Re4", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_cl", "truncated": false}]} +{"ts": 1778658055.2910984, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01XL95PQL1Mqqw4UaJjr5dTk", "input": "{\"pattern\": \"check_return_type|_check_return_type|deserialize\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api_client.py\", \"output_mode\": \"content\", \"head_limit\": 30}", "truncated": false}]} +{"ts": 1778658055.3399844, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XL95PQL1Mqqw4UaJjr5dTk", "is_error": false, "content": "35: deserialize_file,\n216: # deserialize response data\n227: return_data = self.deserialize(\n300: def deserialize(self, response, response_type, _check_type):\n303: :param response: RESTResponse object to be deserialized.\n318: :return: deserialized object.\n324: return deserialize_file(response.data, self.configuration,\n335: deserialized_data = validate_and_convert_types(\n343: return deserialized_data\n366: \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n704: '_check_return_type',\n720: '_check_return_type': (bool,),\n893: _check_type=kwargs['_check_return_type'],", "truncated": false}]} +{"ts": 1778658057.4095178, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01DpSEfkhszAJ4enpmmnavDL", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api_client.py\", \"offset\": 207, \"limit\": 40}", "truncated": false}]} +{"ts": 1778658057.4751542, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DpSEfkhszAJ4enpmmnavDL", "is_error": false, "content": "207\t\n208\t self.last_response = response_data\n209\t\n210\t return_data = response_data\n211\t\n212\t if not _preload_content:\n213\t return (return_data)\n214\t return return_data\n215\t\n216\t # deserialize response data\n217\t if response_type:\n218\t if response_type != (file_type,):\n219\t encoding = \"utf-8\"\n220\t content_type = response_data.getheader('content-type')\n221\t if content_type is not None:\n222\t match = re.search(r\"charset=([a-zA-Z\\-\\d]+)[\\s\\;]?\", content_type)\n223\t if match:\n224\t encoding = match.group(1)\n225\t response_data.data = response_data.data.decode(encoding)\n226\t\n227\t return_data = self.deserialize(\n228\t response_data,\n229\t response_type,\n230\t _check_type\n231\t )\n232\t else:\n233\t return_data = None\n234\t\n235\t if _return_http_data_only:\n236\t return (return_data)\n237\t else:\n238\t return (return_data, response_data.status,\n239\t response_data.getheaders())\n240\t\n241\t def parameters_to_multipart(self, params, collection_types):\n242\t \"\"\"Get parameters as list of tuples, formatting as json if value is collection_types\n243\t\n244\t :param params: Parameters as list of two-tuples\n245\t :param dict collection_types: Parameter collection types\n246\t :return: Parameters as list of tuple or urllib3.fields.RequestField", "truncated": false}]} +{"ts": 1778658059.3788228, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NjhR4wQbjWAcDLifuF9uJc", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api_client.py\", \"offset\": 300, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658059.454762, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NjhR4wQbjWAcDLifuF9uJc", "is_error": false, "content": "300\t def deserialize(self, response, response_type, _check_type):\n301\t \"\"\"Deserializes response into an object.\n302\t\n303\t :param response: RESTResponse object to be deserialized.\n304\t :param response_type: For the response, a tuple containing:\n305\t valid classes\n306\t a list containing valid classes (for list schemas)\n307\t a dict containing a tuple of valid classes as the value\n308\t Example values:\n309\t (str,)\n310\t (Pet,)\n311\t (float, none_type)\n312\t ([int, none_type],)\n313\t ({str: (bool, str, int, float, date, datetime, str, none_type)},)\n314\t :param _check_type: boolean, whether to check the types of the data\n315\t received from the server\n316\t :type _check_type: bool\n317\t\n318\t :return: deserialized object.\n319\t \"\"\"\n320\t # handle file downloading\n321\t # save response body into a tmp file and return the instance\n322\t if response_type == (file_type,):\n323\t content_disposition = response.getheader(\"Content-Disposition\")\n324\t return deserialize_file(response.data, self.configuration,\n325\t content_disposition=content_disposition)\n326\t\n327\t # fetch data from response object\n328\t try:\n329\t received_data = json.loads(response.data)\n330\t except ValueError:\n331\t received_data = response.data\n332\t\n333\t # store our data under the key of 'received_data' so users have some\n334\t # context if they are deserializing a string and the data type is wrong\n335\t deserialized_data = validate_and_convert_types(\n336\t received_data,\n337\t response_type,\n338\t ['received_data'],\n339\t True,\n340\t _check_type,\n341\t configuration=self.configuration\n342\t )\n343\t return deserialized_data\n344\t\n345\t def call_api(\n346\t ", "truncated": true}]} +{"ts": 1778658069.1626291, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me understand how `_check_return_type=False` affects the deserialization. When `_check_return_type=False`, it calls `validate_and_convert_types` with `_check_type=False`. This means the type checking is disabled, but the deserialization still happens.\n\nLooking at the GET response body in the cassette:\n- The response body is a YAML dict (which gets deserialized to JSON in memory)\n- The cassette serializer handles this\n\nWhen the API client gets the response, it calls `json.loads(response.data)` to get `received_data`, then calls `validate_and_convert_types` with the response type.\n\n\nFor `get_organization_layout`, the response type is `DeclarativeOrganization` (or something similar). With `_check_return_type=False`, type checking is skipped but the object still gets constructed as a `DeclarativeOrganization` instance with snake_case attributes. The nested objects like `data_sources` might remain as dicts rather than being fully deserialized into their proper types.\n\nLooking at how `get_declarative_ip_allowlist_policies` handles this, it retrieves the nested policies from the org layout and then explicitly converts each one using `from_api()`. So I need to check how `from_api()` works for these nested objects to understand the proper conversion pattern.", "truncated": false}]} +{"ts": 1778658069.1633177, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the `Base.from_api` method to understand how deserialization works:", "truncated": false}]} +{"ts": 1778658069.4911737, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01LWSq5SYLNH4FRGbNHiqMP2", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/base.py\", \"offset\": 1, \"limit\": 100}", "truncated": false}]} +{"ts": 1778658069.5302095, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LWSq5SYLNH4FRGbNHiqMP2", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport builtins\n5\tfrom typing import Any, TypeVar\n6\t\n7\tfrom attrs import Attribute, asdict, define, field\n8\tfrom cattrs import structure\n9\t\n10\tfrom gooddata_sdk.utils import AllPagedEntities\n11\t\n12\tT = TypeVar(\"T\", bound=\"Base\")\n13\tU = TypeVar(\"U\", bound=\"JsonApiEntityBase\")\n14\t\n15\t\n16\tdef value_in_allowed(instance: type[Base], attribute: Attribute, value: str, client_class: Any | None = None) -> None:\n17\t if client_class is None:\n18\t client_class = instance.client_class()\n19\t allowed_values = client_class.allowed_values.get((attribute.name,))\n20\t if allowed_values is not None and value not in list(allowed_values.values()):\n21\t raise ValueError(\n22\t f\"Allowed values for attribute {attribute.name} are: {', '.join(list(allowed_values.values()))}. \"\n23\t f\"But value {value} was passed.\"\n24\t )\n25\t\n26\t\n27\t@define\n28\tclass Base:\n29\t @classmethod\n30\t def from_api(cls: type[T], entity: dict[str, Any]) -> T:\n31\t \"\"\"\n32\t Creates object from entity passed by client class, which represents it as dictionary.\n33\t \"\"\"\n34\t return structure(entity, cls)\n35\t\n36\t @classmethod\n37\t def from_dict(cls: type[T], data: dict[str, Any], camel_case: bool = True) -> T:\n38\t \"\"\"\n39\t Creates object from dictionary. It needs to be specified if the dictionary is in camelCase or snake_case.\n40\t \"\"\"\n41\t if camel_case:\n42\t data = cls.client_class().from_dict(data, camel_case).to_dict()\n43\t return structure(data, cls)\n44\t\n45\t def to_dict(self, camel_case: bool = True) -> dict[str, Any]:\n46\t \"\"\"\n47\t Converts object into dictionary. Optional argument if the dictionary should be camelCase or snake_case can be\n48\t specified.\n49\t \"\"\"\n50\t # This branch does not have to exist, but in case of camel_case=False it can perform fewer calls\n51\t if not camel_case:", "truncated": true}]} +{"ts": 1778658082.7864625, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Interesting! I see that `from_api` uses `structure(entity, cls)` where `entity` is a dict. So when `from_api` is called in `get_declarative_ip_allowlist_policies`, the `policy` is passed as... what? \n\nLet me trace through:\n1. `org_layout = self._layout_api.get_organization_layout(_check_return_type=False)` \u2192 returns a `DeclarativeOrganization` object (or something similar from the API client)\n2. `policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []` \u2192 returns a list of `DeclarativeIpAllowlistPolicy` objects from the API client\n\n\n3. When `CatalogDeclarativeIpAllowlistPolicy.from_api(policy)` is called, it's trying to structure a `DeclarativeIpAllowlistPolicy` object into `CatalogDeclarativeIpAllowlistPolicy`, but `structure` typically expects a dict. The `_check_return_type=False` flag might be returning raw dicts instead of model objects, which would make this work.\n\nActually, the real issue is that the test fails because `put_declarative_ip_allowlist_policies` sends incomplete credentials\u2014just `username: postgres` without a password\u2014in the org layout PUT request. The fix is to clear partial credentials from data sources before PUTting. Since the cassette has the 400 error baked in, I need to delete it so the pipeline can re-record it with the corrected behavior.\n\nNow I need to check what `org_layout.data_sources` returns when `_check_return_type=False` is used by looking at the `get_organization_layout` method in layout_api.py.", "truncated": false}]} +{"ts": 1778658082.7868505, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the get_organization_layout return type:", "truncated": false}]} +{"ts": 1778658083.4802897, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_012PBtfvkWkANUv41td5cqCU", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 3550, \"limit\": 100}", "truncated": false}]} +{"ts": 1778658083.513738, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_012PBtfvkWkANUv41td5cqCU", "is_error": false, "content": "3550\t def get_organization_layout(\n3551\t self,\n3552\t **kwargs\n3553\t ):\n3554\t \"\"\"Get organization layout # noqa: E501\n3555\t\n3556\t Retrieve complete layout of organization, workspaces, user-groups, etc. # noqa: E501\n3557\t This method makes a synchronous HTTP request by default. To make an\n3558\t asynchronous HTTP request, please pass async_req=True\n3559\t\n3560\t >>> thread = api.get_organization_layout(async_req=True)\n3561\t >>> result = thread.get()\n3562\t\n3563\t\n3564\t Keyword Args:\n3565\t exclude ([str]): [optional]\n3566\t _return_http_data_only (bool): response data without head status\n3567\t code and headers. Default is True.\n3568\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n3569\t will be returned without reading/decoding response data.\n3570\t Default is True.\n3571\t _request_timeout (int/float/tuple): timeout setting for this request. If\n3572\t one number provided, it will be total request timeout. It can also\n3573\t be a pair (tuple) of (connection, read) timeouts.\n3574\t Default is None.\n3575\t _check_input_type (bool): specifies if type checking\n3576\t should be done one the data sent to the server.\n3577\t Default is True.\n3578\t _check_return_type (bool): specifies if type checking\n3579\t should be done one the data received from the server.\n3580\t Default is True.\n3581\t _spec_property_naming (bool): True if the variable names in the input data\n3582\t are serialized names, as specified in the OpenAPI document.\n3583\t False if the variable names in the input data\n3584\t are pythonic names, e.g. snake case (default)\n3585\t _content_type (str/None): force body content-type.\n3586\t Default is None and c", "truncated": true}]} +{"ts": 1778658117.4009137, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The `get_organization_layout` returns `DeclarativeOrganization`. When `_check_return_type=False`, the type checking is disabled but the object is still deserialized as a `DeclarativeOrganization`.\n\nNow, looking at the `DeclarativeOrganization` model:\n- `data_sources` \u2192 list of `DeclarativeDataSource`\n- `ip_allowlist_policies` \u2192 list of `DeclarativeIpAllowlistPolicy`\n\nWhen `_check_return_type=False`, the deserialization might still create `DeclarativeDataSource` objects for each data source. \n\nThese objects would have `authentication_type` and `username` attributes. The real question is whether we can actually modify them. Since `DeclarativeDataSource` inherits from `ModelNormal`, which uses `__setattr__` to manage attribute setting, there's likely validation happening even when `_check_return_type=False` is set. I'm starting to think modifying the `DeclarativeDataSource` object directly might not be the right approach here.\n\nLet me consider a different strategy instead. What if I convert the organization layout to a dictionary, strip out the credentials, and then convert it back? I'm realizing that `_check_return_type=False` doesn't actually change how the response gets deserialized\u2014it just skips type checking. The object still comes back as a `DeclarativeOrganization`. So when I pass a modified `DeclarativeOrganization` object to `set_organization_layout`, I'm still working with the same object structure, just with potentially modified attributes.\n\nThe real issue is that when the API serializes this object for the PUT request, it will include the data sources exactly as they exist in memory\u2014including that `username: postgres` field from the original GET response. So I need to either remove the username from the data source object itself, or prevent it from being serialized in the first place. Let me explore whether I can directly set attributes on a `DeclarativeDataSource` instance to null out the username field, or if I need to look at how the model's attribute as", "truncated": true}]} +{"ts": 1778658117.4035115, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the ModelNormal class to understand attribute setting:", "truncated": false}]} From 220f966bf9acc664e8b06800691d94d5d87ad505 Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Wed, 13 May 2026 07:47:21 +0000 Subject: [PATCH 6/6] fix(gooddata-sdk): [AUTO] fix-agent attempt 2 --- .../layout_ip_allowlist_policies.yaml | 10742 ++++++++++++++++ transcripts/fix-C009-attempt2.jsonl | 133 + 2 files changed, 10875 insertions(+) create mode 100644 transcripts/fix-C009-attempt2.jsonl diff --git a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml index b5ef807d8..7c5cbac33 100644 --- a/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml +++ b/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml @@ -10742,4 +10742,10746 @@ interactions: status: code: 400 message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: + - allowedSources: + - 203.0.113.10/32 + - 198.51.100.0/24 + id: admin-vpn-only + userGroups: + - id: adminGroup + type: userGroup + users: + - id: demo + type: user + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request + - request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: GET + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows + revenue per $ spend, for each campaign, to demonstrate, + how campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and + Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 200 + message: OK + - request: + body: + agents: + - aiKnowledge: true + availableToAll: true + enabled: true + id: default-ai-assistant + name: Default GoodData AI Assistant + skillsMode: all + customGeoCollections: [] + dataSources: + - alternativeDataSourceId: ds-put-abc-id + authenticationType: USERNAME_PASSWORD + id: demo-test-ds + name: demo-test-ds + permissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: USE + schema: demo + type: POSTGRESQL + url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer + username: postgres + exportTemplates: [] + identityProviders: + - id: defaultIdp + idpType: DEX_IDP + ipAllowlistPolicies: [] + jwks: [] + notificationChannels: [] + organization: + allowedOrigins: [] + colorPalettes: [] + cspDirectives: [] + earlyAccess: enableAlerting + earlyAccessValues: + - enableAlerting + - enableSmtp + - enablePreAggregationDatasets + - enableScheduling + - enableCompositeGrain + - enableUserManagement + - enableRawExports + - enableFlexibleDashboardLayout + hostname: localhost + id: default + identityProvider: + id: defaultIdp + type: identityProvider + name: Default Organization + permissions: + - assignee: + id: adminGroup + type: userGroup + name: MANAGE + settings: [] + themes: [] + userGroups: + - id: adminGroup + permissions: [] + - id: adminQA1Group + parents: + - id: adminGroup + type: userGroup + permissions: [] + - id: demoGroup + name: demo group + permissions: [] + - id: visitorsGroup + name: visitors + parents: + - id: demoGroup + type: userGroup + permissions: [] + users: + - id: admin + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + email: demo@example.com + firstname: Demo + id: demo + lastname: User + permissions: [] + settings: [] + userGroups: + - id: adminGroup + type: userGroup + - authId: NORMALIZED_AUTH_ID + id: demo2 + permissions: [] + settings: [] + userGroups: + - id: demoGroup + type: userGroup + workspaceDataFilters: + - columnName: wdf__region + id: wdf__region + title: Customer region + workspace: + id: demo + type: workspace + workspaceDataFilterSettings: + - filterValues: + - West + id: region_west + title: Region West + workspace: + id: demo_west + type: workspace + - columnName: wdf__state + id: wdf__state + title: Customer state + workspace: + id: demo_west + type: workspace + workspaceDataFilterSettings: + - filterValues: + - California + id: region_west_california + title: Region West California + workspace: + id: demo_west_california + type: workspace + workspaces: + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: + - assignee: + id: demo2 + type: user + name: MANAGE + - assignee: + id: demoGroup + type: userGroup + name: ANALYZE + id: demo + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - header: + description: The first insight shows a breakdown of + spend by category and campaign. The second shows revenue + per $ spend, for each campaign, to demonstrate, how + campaigns are successful. + title: Spend breakdown and Revenue + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_per_usd_vs_spend_by_campaign + type: visualizationObject + properties: {} + title: Revenue per $ vs Spend by Campaign + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + title: Campaign + - content: + filterContextRef: + identifier: + id: campaign_name_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: DHO simple + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + plugins: + - plugin: + identifier: + id: dashboard_plugin_1 + type: dashboardPlugin + version: '2' + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: dashboard_plugin + title: Dashboard plugin + - content: + filterContextRef: + identifier: + id: region_filter + type: filterContext + layout: + sections: + - items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_products + type: visualizationObject + properties: {} + title: Top 10 Products + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_trend + type: visualizationObject + properties: {} + title: Revenue Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_breakdown + type: visualizationObject + properties: {} + title: Product Breakdown + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: product_and_category + title: Product & Category + attributeHierarchies: [] + dashboardPlugins: + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_1 + id: dashboard_plugin_1 + title: dashboard_plugin_1 + - content: + url: https://www.example.com + version: '2' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: Testing record dashboard_plugin_2 + id: dashboard_plugin_2 + title: dashboard_plugin_2 + exportDefinitions: [] + filterContexts: + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.month + to: '0' + type: relative + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: campaign_name + type: label + filterElementsBy: [] + localIdentifier: 14b0807447ef4bc28f43e4fc5c337d1d + negativeSelection: true + version: '2' + description: '' + id: campaign_name_filter + title: filterContext + - content: + filters: + - attributeFilter: + attributeElements: + uris: [] + displayForm: + identifier: + id: region + type: label + filterElementsBy: [] + localIdentifier: 2d5ef8df82444f6ba27b45f0990ee6af + negativeSelection: true + version: '2' + description: '' + id: region_filter + title: filterContext + memoryItems: [] + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_active_customers + title: '# of Active Customers' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_orders + title: '# of Orders' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT + {metric/revenue} BY {attribute/customer_id}) > 10000 ' + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: amount_of_top_customers + title: '# of Top Customers' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: amount_of_valid_orders + title: '# of Valid Orders' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: order_amount + title: Order Amount + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue + title: '% Revenue' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + {attribute/products.category}, ALL OTHER) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_in_category + title: '% Revenue in Category' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY + ALL {attribute/product_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product + title: '% Revenue per Product' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("Returned", "Canceled")) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + description: '' + id: revenue + title: Revenue + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Clothing") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-clothing + title: Revenue (Clothing) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ( "Electronics") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-electronic + title: Revenue (Electronic) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Home") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-home + title: Revenue (Home) + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} + IN ("Outdoor") + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue-outdoor + title: Revenue (Outdoor) + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_customer + title: Revenue per Customer + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10 + title: Revenue / Top 10 + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_top_10_percent + title: Revenue / Top 10% + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue + title: Total Revenue + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: total_revenue-no_filters + title: Total Revenue (No Filters) + parameters: [] + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: campaign_spend + title: Campaign Spend + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -12 + granularity: GDC.time.month + to: -1 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: customers_trend + title: Customers Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_breakdown + title: Product Breakdown + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + format: '#,##0.00%' + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_categories_pie_chart + title: Product Categories Pie Chart + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: attribute + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: product_saleability + title: Product Saleability + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: {} + sorts: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_category_trend + title: Revenue by Category Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_by_product + title: Revenue by Product + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: revenue_trend + title: Revenue Trend + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_customers + title: Top 10 Customers + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + createdAt: 2000-01-01 00:00 + createdBy: + id: admin + type: user + id: top_10_products + title: Top 10 Products + ldm: + datasets: + - aggregatedFacts: [] + attributes: + - description: Campaign channel id + id: campaign_channel_id + isNullable: false + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + isNullable: true + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaign_channels + path: + - demo + - campaign_channels + type: dataSource + description: Campaign channels + facts: + - description: Budget + id: budget + isNullable: true + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + isNullable: true + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend + grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + tags: + - Campaign channels + title: Campaign channels + - aggregatedFacts: + - description: Budget Agg + id: budget_agg + sourceColumn: budget + sourceColumnDataType: INT + sourceFactReference: + operation: SUM + reference: + id: budget + type: fact + tags: + - Campaign channels per category + attributes: [] + description: Campaign channels per categories + facts: [] + grain: [] + id: campaign_channels_per_category + precedence: 1 + references: + - identifier: + id: campaign_channels + type: dataset + multivalue: false + sources: + - column: campaign_channel_id + dataType: STRING + isNullable: true + target: + id: campaign_channel_id + type: attribute + sql: + dataSourceId: demo-test-ds + statement: SELECT category, SUM(budget) FROM campaign_channels + GROUP BY category + tags: + - Campaign channels per category + title: Campaign channels per category + - aggregatedFacts: [] + attributes: + - description: Campaign id + id: campaign_id + isNullable: false + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + isNullable: true + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name + dataSourceTableId: + dataSourceId: demo-test-ds + id: campaigns + path: + - demo + - campaigns + type: dataSource + description: Campaigns + facts: [] + grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + tags: + - Campaigns + title: Campaigns + - aggregatedFacts: [] + attributes: + - description: Customer id + id: customer_id + isNullable: false + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + isNullable: true + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + isNullable: true + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + isNullable: true + labels: + - description: Location + id: geo__state__location + isNullable: true + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + valueType: GEO + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State + dataSourceTableId: + dataSourceId: demo-test-ds + id: customers + path: + - demo + - customers + type: dataSource + description: Customers + facts: [] + grain: + - id: customer_id + type: attribute + id: customers + references: [] + tags: + - Customers + title: Customers + - aggregatedFacts: [] + attributes: + - description: Order id + id: order_id + isNullable: true + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + isNullable: false + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + isNullable: true + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status + dataSourceTableId: + dataSourceId: demo-test-ds + id: order_lines + path: + - demo + - order_lines + type: dataSource + description: Order lines + facts: + - description: Price + id: price + isNullable: true + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + isNullable: true + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity + grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + isNullable: true + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + isNullable: true + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + isNullable: true + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + isNullable: true + target: + id: product_id + type: attribute + tags: + - Order lines + title: Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter + - aggregatedFacts: [] + attributes: + - description: Product id + id: product_id + isNullable: false + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + isNullable: true + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + isNullable: true + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category + dataSourceTableId: + dataSourceId: demo-test-ds + id: products + path: + - demo + - products + type: dataSource + description: Products + facts: [] + grain: + - id: product_id + type: attribute + id: products + references: [] + tags: + - Products + title: Products + dateInstances: + - description: '' + granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + tags: + - Date + title: Date + name: Demo + permissions: + - assignee: + id: demo2 + type: user + name: ANALYZE + - assignee: + id: demoGroup + type: userGroup + name: VIEW + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west + model: + analytics: + analyticalDashboardExtensions: + - id: campaign + permissions: + - assigneeRule: + type: allWorkspaceUsers + name: VIEW + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasetExtensions: + - id: order_lines + workspaceDataFilterReferences: + - filterColumn: wdf__state + filterColumnDataType: STRING + filterId: + id: wdf__state + type: workspaceDataFilter + datasets: [] + dateInstances: [] + name: Demo West + parent: + id: demo + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + - automations: [] + customApplicationSettings: [] + filterViews: [] + hierarchyPermissions: [] + id: demo_west_california + model: + analytics: + analyticalDashboardExtensions: [] + analyticalDashboards: [] + attributeHierarchies: [] + dashboardPlugins: [] + exportDefinitions: [] + filterContexts: [] + memoryItems: [] + metrics: [] + parameters: [] + visualizationObjects: [] + ldm: + datasets: [] + dateInstances: [] + name: Demo West California + parent: + id: demo_west + type: workspace + permissions: [] + settings: [] + userDataFilters: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + method: PUT + uri: http://localhost:3000/api/v1/layout/organization + response: + body: + string: + detail: 'Invalid combination of auth properties. Only none, user + password, + token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, + user: , password: , token: , key-pair: , clientId: , + clientSecret: ' + status: 400 + title: Bad Request + traceId: NORMALIZED_TRACE_ID_000000000000 + headers: + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + status: + code: 400 + message: Bad Request version: 1 diff --git a/transcripts/fix-C009-attempt2.jsonl b/transcripts/fix-C009-attempt2.jsonl new file mode 100644 index 000000000..79a2c2b89 --- /dev/null +++ b/transcripts/fix-C009-attempt2.jsonl @@ -0,0 +1,133 @@ +{"ts": 1778658128.172304, "type": "system"} +{"ts": 1778658129.8550375, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me start by reading the failing test to understand what's going wrong.", "truncated": false}]} +{"ts": 1778658130.5511568, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01UpJK6kTjk8muLpp7VaLTYf", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 580, \"limit\": 60}", "truncated": false}]} +{"ts": 1778658130.5971906, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UpJK6kTjk8muLpp7VaLTYf", "is_error": false, "content": "580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"adminGroup\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"demo\", type=\"user\"),\n585\t ],\n586\t ),\n587\t ]\n588\t\n589\t try:\n590\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\n591\t result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n592\t assert len(result) == 1\n593\t assert result[0].id == \"admin-vpn-only\"\n594\t assert result[0].allowed_sources == [\"203.0.113.10/32\", \"198.51.100.0/24\"]\n595\t assert len(result[0].user_groups) == 1\n596\t assert result[0].user_groups[0].id == \"adminGroup\"\n597\t assert len(result[0].users) == 1\n598\t assert result[0].users[0].id == \"demo\"\n599\t finally:\n600\t sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n601\t", "truncated": false}]} +{"ts": 1778658132.487697, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01TahnLFxmuRUK4HAsckxVDC", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"offset\": 550, \"limit\": 35}", "truncated": false}]} +{"ts": 1778658132.516303, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TahnLFxmuRUK4HAsckxVDC", "is_error": false, "content": "550\t# identifiers=identifiers,\n551\t# oauth_client_id=oauth_client_id,\n552\t# oauth_client_secret=oauth_client_secret,\n553\t# oauth_issuer_location=oauth_issuer_location,\n554\t# ),\n555\t# ]\n556\t# sdk.catalog_organization.put_declarative_identity_providers(identity_providers_e)\n557\t# identity_providers_o = sdk.catalog_organization.get_declarative_identity_providers()\n558\t# assert identity_providers_o[0].id == identity_providers_e[0].id\n559\t# assert identity_providers_o[0].custom_claim_mapping == identity_providers_e[0].custom_claim_mapping\n560\t# assert identity_providers_o[0].identifiers == identity_providers_e[0].identifiers\n561\t# assert identity_providers_o[0].oauth_client_id == identity_providers_e[0].oauth_client_id\n562\t# assert identity_providers_o[0].oauth_client_secret is None\n563\t# assert identity_providers_o[0].oauth_issuer_location == identity_providers_e[0].oauth_issuer_location\n564\t# finally:\n565\t# sdk.catalog_organization.put_declarative_identity_providers([])\n566\t# idps = sdk.catalog_organization.get_declarative_identity_providers()\n567\t# assert len(idps) == 0\n568\t\n569\t\n570\t@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\n571\tdef test_layout_ip_allowlist_policies(test_config):\n572\t sdk = GoodDataSdk.create(host_=test_config[\"host\"], token_=test_config[\"token\"])\n573\t\n574\t original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\n575\t\n576\t new_policies = [\n577\t CatalogDeclarativeIpAllowlistPolicy(\n578\t id=\"admin-vpn-only\",\n579\t allowed_sources=[\"203.0.113.10/32\", \"198.51.100.0/24\"],\n580\t user_groups=[\n581\t CatalogDeclarativeUserGroupIdentifier(id=\"adminGroup\", type=\"userGroup\"),\n582\t ],\n583\t users=[\n584\t CatalogUserIdentifier(id=\"de", "truncated": true}]} +{"ts": 1778658137.0965571, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The test is failing because when restoring the `original_policies`, the API is returning a 400 error. The error says:\n\n\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \"\n\nThis error is from a PUT request to `set_organization_layout`. This is calling `set_organization_layout` instead of a more specific endpoint.\n\n\nNow I need to check the service implementation for `put_declarative_ip_allowlist_policies` to understand what's happening.", "truncated": false}]} +{"ts": 1778658137.1102817, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01965AHvJidtcnDZzoYh3ALV", "input": "{\"pattern\": \"put_declarative_ip_allowlist_policies\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658137.1415513, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Xu9Vy9cofS2RXv9MQwTAtR", "input": "{\"pattern\": \"ip_allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658137.1421459, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01965AHvJidtcnDZzoYh3ALV", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/test_catalog_organization.py:590: sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:600: sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:760: def put_declarative_ip_allowlist_policies(", "truncated": false}]} +{"ts": 1778658137.2406247, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Xu9Vy9cofS2RXv9MQwTAtR", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/test_catalog_organization.py:570:@gd_vcr.use_cassette(str(_fixtures_dir / \"layout_ip_allowlist_policies.yaml\"))\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:571:def test_layout_ip_allowlist_policies(test_config):\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:574: original_policies = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:590: sdk.catalog_organization.put_declarative_ip_allowlist_policies(new_policies)\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:591: result = sdk.catalog_organization.get_declarative_ip_allowlist_policies()\npackages/gooddata-sdk/tests/catalog/test_catalog_organization.py:600: sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:34:from gooddata_sdk.catalog.organization.layout.ip_allowlist_policy import CatalogDeclarativeIpAllowlistPolicy\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:747: def get_declarative_ip_allowlist_policies(self) -> list[CatalogDeclarativeIpAllowlistPolicy]:\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:757: policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:760: def put_declarative_ip_allowlist_policies(\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:761: self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:765: Reads the full organization layout, replaces the ip_allowlist_policies field,\npackages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py:769: ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\npackages/go", "truncated": true}]} +{"ts": 1778658139.1359537, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01SXRjh2hMeZaLbNfK242DfX", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 745, \"limit\": 45}", "truncated": false}]} +{"ts": 1778658139.1483042, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01SXRjh2hMeZaLbNfK242DfX", "is_error": false, "content": "745\t raise ValueError(f\"Error switching active identity provider: {str(e)}\")\n746\t\n747\t def get_declarative_ip_allowlist_policies(self) -> list[CatalogDeclarativeIpAllowlistPolicy]:\n748\t \"\"\"Get all declarative IP allowlist policies for the current organization.\n749\t\n750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n778\t", "truncated": false}]} +{"ts": 1778658146.6000776, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the issue. The `put_declarative_ip_allowlist_policies` reads the full organization layout and then sets it back. The error message says:\n\n\"Invalid combination of auth properties. Only none, user + password, token, key-pair or client id + secret are allowed. Datasource: demo-test-ds, user: , password: , token: , key-pair: , clientId: , clientSecret: \"\n\nThis is a 400 error because the organization layout contains a datasource (`demo-test-ds`) that has a `username` set but when you do a PUT, you need to provide either the full combination (user + password) or no auth. \n\nThe root cause is that when retrieving the org layout, datasource passwords are masked and never returned, so when I write it back, the username remains but the password is missing\u2014an invalid state the API won't accept. This is a classic read-modify-write problem with sensitive data. I need to check how other PUT operations handle this scenario to find the right approach.", "truncated": false}]} +{"ts": 1778658146.6060953, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_0155xugKzG1dRLUj1tUdA9g2", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658146.612122, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0155xugKzG1dRLUj1tUdA9g2", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport functools\n5\tfrom typing import Any, Literal\n6\t\n7\tfrom gooddata_api_client.exceptions import NotFoundException\n8\tfrom gooddata_api_client.model.declarative_export_templates import DeclarativeExportTemplates\n9\tfrom gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels\n10\tfrom gooddata_api_client.model.json_api_csp_directive_in_document import JsonApiCspDirectiveInDocument\n11\tfrom gooddata_api_client.model.json_api_export_template_in_document import JsonApiExportTemplateInDocument\n12\tfrom gooddata_api_client.model.json_api_export_template_post_optional_id_document import (\n13\t JsonApiExportTemplatePostOptionalIdDocument,\n14\t)\n15\tfrom gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument\n16\tfrom gooddata_api_client.model.json_api_organization_patch import JsonApiOrganizationPatch\n17\tfrom gooddata_api_client.model.json_api_organization_patch_document import JsonApiOrganizationPatchDocument\n18\tfrom gooddata_api_client.model.json_api_organization_setting_in_document import JsonApiOrganizationSettingInDocument\n19\tfrom gooddata_api_client.model.switch_identity_provider_request import SwitchIdentityProviderRequest\n20\t\n21\tfrom gooddata_sdk import CatalogDeclarativeExportTemplate, CatalogExportTemplate\n22\tfrom gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase\n23\tfrom gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective\n24\tfrom gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider\n25\tfrom gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument\n26\tfrom gooddata_sdk.catalog.organization.entity_model.llm_provider import (\n27\t CatalogLlmProvider,\n28\t CatalogLlmProviderDocument,\n29\t CatalogLlmProviderPatch,\n30\t CatalogLlmProviderPatchDocument,\n31\t)\n32\tfrom gooddata_sdk.c", "truncated": true}]} +{"ts": 1778658146.613672, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HBe377TCqhMzCCqG6xKcnx", "input": "{\"pattern\": \"set_organization_layout\\\\|get_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658146.63869, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HBe377TCqhMzCCqG6xKcnx", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778658149.0903397, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01LmSadAKPhJmpYu8tR7Z684", "input": "{\"pattern\": \"set_organization_layout\\\\|get_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\", \"head_limit\": 0}", "truncated": false}]} +{"ts": 1778658149.208318, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01LmSadAKPhJmpYu8tR7Z684", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778658151.0275986, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01Seo7dCoocGNifCVZTterGu", "input": "{\"command\": \"grep -n \\\"set_organization_layout\\\\|get_organization_layout\\\\|_layout_api\\\" /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py | head -30\"}", "truncated": false}]} +{"ts": 1778658151.0614524, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Seo7dCoocGNifCVZTterGu", "is_error": true, "content": "Blocked: grep -n \"set_organization_layout\\|get_organization_layout\\|_layout_api\" /home/ru", "truncated": false}]} +{"ts": 1778658152.9363732, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_018yh11PzNAPpJMXCZJ72jW6", "input": "{\"pattern\": \"_layout_api\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658152.9701207, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_018yh11PzNAPpJMXCZJ72jW6", "is_error": false, "content": "644: for nc in self._layout_api.get_notification_channels_layout().notification_channels\n661: self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))\n672: CatalogDeclarativeIdentityProvider.from_api(idp) for idp in self._layout_api.get_identity_providers_layout()\n687: self._layout_api.set_identity_providers(declarative_identity_provider=api_idps)\n697: export_templates_api = self._layout_api.get_export_templates_layout()\n718: self._layout_api.set_export_templates(\n756: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n775: org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n777: self._layout_api.set_organization_layout(org_layout, _check_return_type=False)", "truncated": false}]} +{"ts": 1778658158.4884343, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The issue is clear now. The `put_declarative_ip_allowlist_policies` method does a read-modify-write on the full organization layout. When it reads the organization layout, the datasource passwords are masked/not returned. Then when it writes back the full layout, the API rejects it because the datasource (`demo-test-ds`) has a username but no password, which is an invalid combination.\n\nThe fix should not read the full org layout and write it back. Instead, it should use a more targeted API that only sets the IP allowlist policies, if one exists. \n\nLet me check what API endpoints are available in the layout_api to see if there's a dedicated method for updating just the IP allowlist policies.", "truncated": false}]} +{"ts": 1778658158.4954226, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01DvirAig61gegGNhEyB21CE", "input": "{\"command\": \"ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/gooddata_api_client/api/layout_api.py 2>/dev/null && echo \\\"EXISTS\\\"\"}", "truncated": false}]} +{"ts": 1778658158.5212982, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DvirAig61gegGNhEyB21CE", "is_error": true, "content": "Blocked: ls /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/.tox/py312/lib/p", "truncated": false}]} +{"ts": 1778658160.2775197, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01BA4EfiB7DnDBCdqELGWh3o", "input": "{\"pattern\": \"**/*.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client/gooddata_api_client/api\"}", "truncated": false}]} +{"ts": 1778658160.3073556, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01BA4EfiB7DnDBCdqELGWh3o", "is_error": true, "content": "Directory does not exist: /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-api-client/gooddata_api_client/api. Note: your current working directory is /home/runner/_work/gdc-nas/gdc-nas/sdk.", "truncated": false}]} +{"ts": 1778658162.089768, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01GBmF2winZ84VfZQW26aYvM", "input": "{\"pattern\": \"**/layout_api.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778658162.1251004, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01GBmF2winZ84VfZQW26aYvM", "is_error": false, "content": "gooddata-api-client/build/lib/gooddata_api_client/api/layout_api.py\ngooddata-api-client/gooddata_api_client/api/layout_api.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/gooddata_api_client/api/layout_api.py", "truncated": false}]} +{"ts": 1778658164.6073005, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01X7Ey5BHsov4mreAgWLbC2L", "input": "{\"command\": \"python3 -c \\\"import re; content=open('/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py').read(); matches=[m.group(1) for m in re.finditer(r'def (set_\\\\w+|put_\\\\w+|patch_\\\\w+)', content)]; print('\\\\n'.join(matches))\\\"\"}", "truncated": false}]} +{"ts": 1778658164.6417167, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01X7Ey5BHsov4mreAgWLbC2L", "is_error": true, "content": "Blocked: python3 -c \"import re; content=open('/home/runner/_work/gdc-nas/gdc-nas/sdk/good", "truncated": false}]} +{"ts": 1778658167.1447573, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01KD4BWxCueH82oN5dFztDgH", "input": "{\"pattern\": \"def set_|def put_|def patch_\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658167.187173, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01KD4BWxCueH82oN5dFztDgH", "is_error": false, "content": "4514: def put_data_source_statistics(\n4601: def put_data_sources_layout(\n4684: def put_user_groups_layout(\n4767: def put_users_layout(\n4850: def put_users_user_groups_layout(\n4933: def put_workspace_layout(\n5020: def set_agents_layout(\n5103: def set_analytics_model(\n5190: def set_automations(\n5277: def set_custom_geo_collections(\n5360: def set_data_source_permissions(\n5447: def set_export_templates(\n5530: def set_filter_views(\n5617: def set_identity_providers(\n5700: def set_logical_model(\n5787: def set_notification_channels(\n5870: def set_organization_layout(\n5953: def set_organization_permissions(\n6036: def set_user_data_filters(\n6123: def set_user_group_permissions(\n6210: def set_user_permissions(\n6297: def set_workspace_data_filters_layout(\n6380: def set_workspace_permissions(\n6467: def set_workspaces_layout(", "truncated": false}]} +{"ts": 1778658181.0075648, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I don't see a specific `set_ip_allowlist_policies` or similar method in the layout API. The only option available is `set_organization_layout` which sets the full organization layout.\n\nLet me look at the error more carefully. The issue is that when getting the org layout, the datasource passwords are masked/not returned. Then when PUT-ing back the full layout, the API rejects it because a datasource (`demo-test-ds`) has a username but no password.\n\nWait, but the error is in the `put_declarative_ip_allowlist_policies` method calling `set_organization_layout`. The original test logic:\n\n\n1. Get original_policies\n2. Try: put new_policies \u2192 assert result \u2192 put original_policies back\n3. The PUT in the finally block fails because the org layout contains sensitive credentials that got masked when fetching\n\nThe problem is clear now: when I fetch the organization layout, datasource passwords are redacted, so when I try to restore the original layout, the API sees a datasource with a username but no password and rejects it. I need to find how other functions handle this\u2014maybe there's an exclude_sensitive parameter or some other workaround for dealing with masked credentials. When you then PUT that back, the API says \"invalid combination\".\n\nBut wait - this should also happen in `put_declarative_ip_allowlist_policies` in the `try` block, not just the `finally` block. Let me re-read the error:\n\n```\ntests/catalog/test_catalog_organization.py:600: in test_layout_ip_allowlist_policies\n sdk.catalog_organization.put_declarative_ip_allowlist_policies(original_policies)\n.tox/py312/lib/python3.12/site-packages/gooddata_sdk/catalog/organization/service.py:777: in put_declarative_ip_allowlist_policies\n self._layout_api.set_organization_layout(org_layout, _check_return_type=False)\n```\n\nThe error is in line 600, which is the `finally` block - restoring the original_policies. But the same PUT is used in line 590 as well... The assertion at line 592 passes, which means the first call suc", "truncated": true}]} +{"ts": 1778658181.0142188, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_0118zDCo9qhr62ZeF1aC9Ebz", "input": "{\"pattern\": \"**/layout_ip_allowlist_policies.yaml\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778658181.0457087, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_0118zDCo9qhr62ZeF1aC9Ebz", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml", "truncated": false}]} +{"ts": 1778658182.6371295, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01HU4nZbWrf4CkP18wnmRe86", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\"}", "truncated": false}]} +{"ts": 1778658182.6715636, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HU4nZbWrf4CkP18wnmRe86", "is_error": true, "content": "File content (927.3KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.", "truncated": false}]} +{"ts": 1778658184.659972, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01T9S4ijN6CtxzbQoH3gmWpw", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 1, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658184.6903453, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01T9S4ijN6CtxzbQoH3gmWpw", "is_error": false, "content": "1\tinteractions:\n2\t - request:\n3\t body: null\n4\t headers:\n5\t Accept:\n6\t - application/json\n7\t Accept-Encoding:\n8\t - br, gzip, deflate\n9\t X-GDC-VALIDATE-RELATIONS:\n10\t - 'true'\n11\t X-Requested-With:\n12\t - XMLHttpRequest\n13\t method: GET\n14\t uri: http://localhost:3000/api/v1/layout/organization\n15\t response:\n16\t body:\n17\t string:\n18\t agents:\n19\t - aiKnowledge: true\n20\t availableToAll: true\n21\t enabled: true\n22\t id: default-ai-assistant\n23\t name: Default GoodData AI Assistant\n24\t skillsMode: all\n25\t customGeoCollections: []\n26\t dataSources:\n27\t - alternativeDataSourceId: ds-put-abc-id\n28\t authenticationType: USERNAME_PASSWORD\n29\t id: demo-test-ds\n30\t name: demo-test-ds\n31\t permissions:\n32\t - assignee:\n33\t id: demo2\n34\t type: user\n35\t name: MANAGE\n36\t - assignee:\n37\t id: demoGroup\n38\t type: userGroup\n39\t name: USE\n40\t schema: demo\n41\t type: POSTGRESQL\n42\t url: jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\n43\t username: postgres\n44\t exportTemplates: []\n45\t identityProviders:\n46\t - id: defaultIdp\n47\t idpType: DEX_IDP\n48\t ipAllowlistPolicies: []\n49\t jwks: []\n50\t notificationChannels: []", "truncated": false}]} +{"ts": 1778658190.084132, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand the issue! Looking at the cassette, the organization layout response contains a datasource `demo-test-ds` with `authenticationType: USERNAME_PASSWORD` and `username: postgres`, but no password (it's not in the cassette response). This is the \"masked\" credential.\n\nSo when `put_declarative_ip_allowlist_policies` does:\n1. `get_organization_layout` \u2192 returns layout with datasource that has username but no password\n2. Sets `ip_allowlist_policies` on the layout\n\n\n3. `set_organization_layout(org_layout)` \u2192 400 because username without password\n\nI need to check what interactions are actually recorded in the cassette to see if there's a workaround or if I'm missing something about how the credentials are being handled.", "truncated": false}]} +{"ts": 1778658190.0924082, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_019dGrhVYzfWzvdLawmAS9oh", "input": "{\"pattern\": \"method: (GET|POST|PUT|DELETE|PATCH)\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658190.1181717, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_019dGrhVYzfWzvdLawmAS9oh", "is_error": false, "content": "13: method: GET\n2158: method: GET\n6425: method: PUT\n6462: method: GET\n10719: method: PUT\n10756: method: GET\n12900: method: GET\n17167: method: PUT\n17204: method: GET\n21461: method: PUT", "truncated": false}]} +{"ts": 1778658196.117602, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look at the structure of the cassette interactions. It seems to have:\n1. GET (line 13)\n2. GET (line 2158)\n3. PUT (line 6425)\n4. GET (line 6462)\n5. PUT (line 10719)\n6. GET (line 10756)\n7. GET (line 12900)\n8. PUT (line 17167)\n9. GET (line 17204)\n10. PUT (line 21461)\n\nThe test flow is:\n1. `get_declarative_ip_allowlist_policies()` \u2192 calls `get_organization_layout` (GET #1)\n\n\n2. `put_declarative_ip_allowlist_policies(new_policies)` \u2192 calls `get_organization_layout` (GET) + `set_organization_layout` (PUT)\n3. `get_declarative_ip_allowlist_policies()` \u2192 calls `get_organization_layout` (GET)\n4. `put_declarative_ip_allowlist_policies(original_policies)` \u2192 calls `get_organization_layout` (GET) + `set_organization_layout` (PUT)\n\nThe cassette has more GETs and PUTs than expected, so I should check the actual URIs to understand what's happening\u2014there might be retries or additional calls I'm not accounting for.", "truncated": false}]} +{"ts": 1778658196.126212, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01UffKXjD6ojk4Js4PZbXHrD", "input": "{\"pattern\": \"method:|uri:\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658196.1511416, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01UffKXjD6ojk4Js4PZbXHrD", "is_error": false, "content": "13: method: GET\n14: uri: http://localhost:3000/api/v1/layout/organization\n2158: method: GET\n2159: uri: http://localhost:3000/api/v1/layout/organization\n6425: method: PUT\n6426: uri: http://localhost:3000/api/v1/layout/organization\n6462: method: GET\n6463: uri: http://localhost:3000/api/v1/layout/organization\n10719: method: PUT\n10720: uri: http://localhost:3000/api/v1/layout/organization\n10756: method: GET\n10757: uri: http://localhost:3000/api/v1/layout/organization\n12900: method: GET\n12901: uri: http://localhost:3000/api/v1/layout/organization\n17167: method: PUT\n17168: uri: http://localhost:3000/api/v1/layout/organization\n17204: method: GET\n17205: uri: http://localhost:3000/api/v1/layout/organization\n21461: method: PUT\n21462: uri: http://localhost:3000/api/v1/layout/organization", "truncated": false}]} +{"ts": 1778658222.6353385, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the cassette has 10 interactions, all to `http://localhost:3000/api/v1/layout/organization`. The expected flow should be:\n\nTest flow with current code:\n1. `get_declarative_ip_allowlist_policies()` \u2192 GET org_layout\n2. `put_declarative_ip_allowlist_policies(new_policies)` \u2192 GET org_layout + PUT org_layout\n3. `get_declarative_ip_allowlist_policies()` \u2192 GET org_layout\n\n\n4. `put_declarative_ip_allowlist_policies(original_policies)` \u2192 GET org_layout + PUT org_layout\n\nThat's 4 GETs and 2 PUTs for 6 total interactions, but the cassette has 10. The test is using `@gd_vcr.use_cassette` which should play back all recorded interactions, but it's failing because the current code isn't making enough requests to consume them all.\n\nLooking at the error, the test is hitting a live server with a 400 error instead of using the cassette. The cassette should intercept the `set_organization_layout` call, but it seems like the cassette is running out of interactions\u2014if the code makes more requests than what's recorded, the VCR library will fall back to making actual HTTP requests.\n\nLet me count the interactions in the cassette more carefully. I'm seeing a mix of GETs and PUTs recorded, but I need to verify the exact count and whether the cassette was recorded with a different implementation than what's currently running.\n\nThe key issue is that the code is making a real HTTP request to localhost:3000 and getting a 400 error, which means the cassette has run out of recorded interactions. So the cassette must have fewer interactions than what the current code flow is attempting to make. Looking at the actual implementation, `put_declarative_ip_allowlist_policies` does a GET to fetch the org layout, modifies the policies, then PUTs it back. The test calls `get_declarative_ip_allowlist_policies` first, then `put_declarative_ip_allowlist_policies`, so I need to trace through exactly how many HTTP calls that generates and compare it to what's recorded in the cassette. The error trace shows th", "truncated": true}]} +{"ts": 1778658222.6404736, "type": "assistant", "blocks": [{"type": "text", "text": "Let me look at the installed service.py to understand the version being tested:", "truncated": false}]} +{"ts": 1778658222.6771126, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Bash", "id": "toolu_01K3EFc9L2qcC9a7MrYT6P2y", "input": "{\"command\": \"wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/gooddata_sdk/catalog/organization/service.py 2>/dev/null && tail -30 /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/gooddata_sdk/catalog/organization/service.py 2>/dev/null || echo \\\"not accessible\\\"\"}", "truncated": false}]} +{"ts": 1778658222.716143, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01K3EFc9L2qcC9a7MrYT6P2y", "is_error": true, "content": "Blocked: wc -l /home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/.tox/py312/li", "truncated": false}]} +{"ts": 1778658224.7530277, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01VGCyVELFXPJdTm1MsxBcBQ", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py\", \"offset\": 740, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658224.7838168, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01VGCyVELFXPJdTm1MsxBcBQ", "is_error": false, "content": "740\t except NotFoundException:\n741\t raise ValueError(\n742\t f\"Cannot switch to identity provider {identity_provider_id}. This identity provider does not exist.\"\n743\t )\n744\t except Exception as e:\n745\t raise ValueError(f\"Error switching active identity provider: {str(e)}\")\n746\t\n747\t def get_declarative_ip_allowlist_policies(self) -> list[CatalogDeclarativeIpAllowlistPolicy]:\n748\t \"\"\"Get all declarative IP allowlist policies for the current organization.\n749\t\n750\t IP allowlist policies are returned as part of the full organization layout.\n751\t\n752\t Returns:\n753\t list[CatalogDeclarativeIpAllowlistPolicy]:\n754\t List of declarative IP allowlist policies.\n755\t \"\"\"\n756\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n757\t policies = getattr(org_layout, \"ip_allowlist_policies\", None) or []\n758\t return [CatalogDeclarativeIpAllowlistPolicy.from_api(policy) for policy in policies]\n759\t\n760\t def put_declarative_ip_allowlist_policies(\n761\t self, ip_allowlist_policies: list[CatalogDeclarativeIpAllowlistPolicy]\n762\t ) -> None:\n763\t \"\"\"Put declarative IP allowlist policies for the current organization.\n764\t\n765\t Reads the full organization layout, replaces the ip_allowlist_policies field,\n766\t and writes the full layout back. All other organization settings are preserved.\n767\t\n768\t Args:\n769\t ip_allowlist_policies (list[CatalogDeclarativeIpAllowlistPolicy]):\n770\t List of declarative IP allowlist policies to set.\n771\t\n772\t Returns:\n773\t None\n774\t \"\"\"\n775\t org_layout = self._layout_api.get_organization_layout(_check_return_type=False)\n776\t org_layout.ip_allowlist_policies = [policy.to_api() for policy in ip_allowlist_policies]\n777\t self._layout_api.set_organization_layout(org_layout, _check_return_type=Fa", "truncated": true}]} +{"ts": 1778658234.424368, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the current implementation reads the full org layout and writes it back. The cassette was recorded with 10 interactions: GET, GET, PUT, GET, PUT, GET, GET, PUT, GET, PUT.\n\nThe test flow with current code makes:\n1. `get_declarative_ip_allowlist_policies()` \u2192 GET #1 (line 574)\n2. `put_declarative_ip_allowlist_policies(new_policies)` \u2192 GET #2 + PUT #3 (line 590) \n3. `get_declarative_ip_allowlist_policies()` \u2192 GET #4 (line 591)\n\n\n4. `put_declarative_ip_allowlist_policies(original_policies)` \u2192 GET #5 + PUT #6 (line 600)\n\nThat's 6 interactions so far, but the cassette has 10 total. Looking at the actual recorded sequence, I see it's GET, GET, PUT, GET, PUT, GET, GET, PUT, GET, PUT \u2014 so there are more interactions happening than what my current code path accounts for. The test must be failing because it's trying to make a 7th call that doesn't match what's recorded next in the cassette.\n\nLet me trace through what the code actually does: first GET for the initial policy check, then GET inside the put operation for the new policies, PUT to set those, then GET for the result check, then GET inside put for the original policies, and PUT to restore them. That's 4 GETs and 2 PUTs. But the cassette shows a different pattern \u2014 maybe the original implementation was structured differently, or there's additional setup happening in conftest that's adding extra calls. Let me check the conftest teardown code to see if that's where the extra interactions are coming from.", "truncated": false}]} +{"ts": 1778658234.441746, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01JMb6mizVUGhzjPMp6VSfGR", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 270, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658234.470523, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01JMb6mizVUGhzjPMp6VSfGR", "is_error": false, "content": "270\t logger.error(f\"Snapshot capture failed [notification_channels]: {e}\")\n271\t\n272\t # Per-workspace permissions\n273\t ws_permissions = {}\n274\t try:\n275\t for ws in sdk.catalog_workspace.list_workspaces():\n276\t try:\n277\t ws_permissions[ws.id] = sdk.catalog_permission.get_declarative_permissions(ws.id)\n278\t except Exception as e: # noqa: PERF203\n279\t logger.warning(f\"Could not capture permissions for workspace {ws.id}: {e}\")\n280\t except Exception as e:\n281\t logger.error(f\"Snapshot capture failed [workspace list for permissions]: {e}\")\n282\t snapshot[\"ws_permissions\"] = ws_permissions\n283\t\n284\t logger.info(\"Session snapshot captured\")\n285\t\n286\t # --- Tests run ---\n287\t yield snapshot\n288\t\n289\t # --- Restore (only if failures) ---\n290\t if not _session_has_failures:\n291\t logger.info(\"All tests passed \u2014 skipping session restore\")\n292\t return\n293\t\n294\t logger.warning(\"Test failures detected \u2014 restoring session snapshot...\")\n295\t\n296\t # Restore order matters: users/groups \u2192 data sources \u2192 workspaces \u2192\n297\t # workspace data filters \u2192 org permissions \u2192 notification channels \u2192\n298\t # per-workspace permissions\n299\t\n300\t if \"users_groups\" in snapshot:\n301\t try:\n302\t sdk.catalog_user.put_declarative_users_user_groups(snapshot[\"users_groups\"])\n303\t logger.info(\"Restored [users_groups]\")\n304\t except Exception as e:\n305\t logger.error(f\"RESTORE FAILED [users_groups]: {e}\")\n306\t\n307\t if \"data_sources\" in snapshot:\n308\t try:\n309\t sdk.catalog_data_source.put_declarative_data_sources(snapshot[\"data_sources\"], _credentials_path)\n310\t logger.info(\"Restored [data_sources]\")\n311\t except Exception as e:\n312\t logger.error(f\"RESTORE FAILED [data_sources]: {e}\")\n313\t\n314\t if \"workspaces\" in snapshot:\n315\t try:\n316\t sdk.catalog_workspace.put_declarativ", "truncated": true}]} +{"ts": 1778658236.2565567, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_011uS2rptuuXvsMjXcXpD6mj", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 315, \"limit\": 80}", "truncated": false}]} +{"ts": 1778658236.2868376, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011uS2rptuuXvsMjXcXpD6mj", "is_error": false, "content": "315\t try:\n316\t sdk.catalog_workspace.put_declarative_workspaces(snapshot[\"workspaces\"])\n317\t logger.info(\"Restored [workspaces]\")\n318\t except Exception as e:\n319\t logger.error(f\"RESTORE FAILED [workspaces]: {e}\")\n320\t\n321\t if \"workspace_data_filters\" in snapshot:\n322\t try:\n323\t sdk.catalog_workspace.put_declarative_workspace_data_filters(snapshot[\"workspace_data_filters\"])\n324\t logger.info(\"Restored [workspace_data_filters]\")\n325\t except Exception as e:\n326\t logger.error(f\"RESTORE FAILED [workspace_data_filters]: {e}\")\n327\t\n328\t if \"org_permissions\" in snapshot:\n329\t try:\n330\t sdk.catalog_permission.put_declarative_organization_permissions(snapshot[\"org_permissions\"])\n331\t logger.info(\"Restored [org_permissions]\")\n332\t except Exception as e:\n333\t logger.error(f\"RESTORE FAILED [org_permissions]: {e}\")\n334\t\n335\t if \"notification_channels\" in snapshot:\n336\t try:\n337\t sdk.catalog_organization.put_declarative_notification_channels(snapshot[\"notification_channels\"])\n338\t logger.info(\"Restored [notification_channels]\")\n339\t except Exception as e:\n340\t logger.error(f\"RESTORE FAILED [notification_channels]: {e}\")\n341\t\n342\t for ws_id, perms in snapshot.get(\"ws_permissions\", {}).items():\n343\t try:\n344\t sdk.catalog_permission.put_declarative_permissions(ws_id, perms)\n345\t logger.info(f\"Restored [permissions for {ws_id}]\")\n346\t except Exception as e: # noqa: PERF203\n347\t logger.warning(f\"RESTORE FAILED [permissions for {ws_id}]: {e}\")\n348\t", "truncated": false}]} +{"ts": 1778658246.526303, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I see. The conftest doesn't have an IP allowlist policies restore. The conftest teardown runs after the test and also under the session fixture, so it might make additional calls.\n\nBut wait, the problem is more fundamental. The cassette was recorded with a specific sequence of interactions. The issue is that the cassette was recorded with a different implementation (perhaps one that uses `put_ip_allowlist_policies` as a separate API call, or makes fewer GET calls). \n\nBut now the implementation uses `get_organization_layout` + `set_organization_layout` for both GET and PUT operations, and each PUT makes an extra GET, consuming more cassette entries than were expected.\n \nLet me trace through the actual sequence: the test makes a GET, then a PUT (which itself does a GET first), then another GET, then a final PUT with its own GET. That's six total interactions with the cassette, but there are ten recorded, so there's room for the conftest teardown and other operations before we hit the limit.\n\nThe key question is how VCR is configured\u2014if it's in \"none\" mode, it'll error on any request beyond what's recorded, but if it's in \"new_episodes\" mode, it'll make real HTTP calls for the extras. I need to check the actual VCR configuration in `gd_vcr`.", "truncated": false}]} +{"ts": 1778658246.5416713, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01F7a81P6WefP9mdRDDLg6KL", "input": "{\"pattern\": \"**/conftest.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\"}", "truncated": false}]} +{"ts": 1778658246.5686505, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01F7a81P6WefP9mdRDDLg6KL", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/conftest.py\npackages/gooddata-sdk/tests/conftest.py", "truncated": false}]} +{"ts": 1778658248.1426349, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01KfETFGTut6coarZjFGTKfu", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/conftest.py\"}", "truncated": false}]} +{"ts": 1778658248.1890478, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01KfETFGTut6coarZjFGTKfu", "is_error": false, "content": "1\t# (C) 2026 GoodData Corporation\n2\t\"\"\"\n3\tShared test fixtures for catalog tests.\n4\t\n5\tProvides:\n6\t- safe_delete: cleanup utility that swallows exceptions\n7\t- sdk: session-scoped GoodDataSdk instance\n8\t- Snapshot/restore fixtures for staging-safe testing\n9\t\"\"\"\n10\t\n11\tfrom __future__ import annotations\n12\t\n13\timport copy\n14\timport logging\n15\tfrom pathlib import Path\n16\tfrom typing import Any, Callable\n17\t\n18\timport pytest\n19\tfrom gooddata_sdk import CatalogDeclarativeDataSources, GoodDataSdk\n20\tfrom tests_support.file_utils import load_json\n21\t\n22\tlogger = logging.getLogger(__name__)\n23\t\n24\t_current_dir = Path(__file__).parent.absolute()\n25\t_credentials_path = _current_dir / \"load\" / \"data_source_credentials\" / \"data_sources_credentials.yaml\"\n26\t\n27\t\n28\tdef _capture_workspace_permissions(sdk: GoodDataSdk, workspaces: list) -> dict:\n29\t \"\"\"Capture permissions for all workspaces, skipping failures.\"\"\"\n30\t ws_permissions: dict = {}\n31\t for ws in workspaces:\n32\t try:\n33\t ws_permissions[ws.id] = sdk.catalog_permission.get_declarative_permissions(ws.id)\n34\t except Exception as e: # noqa: PERF203\n35\t logger.warning(f\"Could not capture permissions for workspace {ws.id}: {e}\")\n36\t return ws_permissions\n37\t\n38\t\n39\tdef _restore_workspace_permissions(sdk: GoodDataSdk, ws_permissions: dict) -> None:\n40\t \"\"\"Restore permissions for all workspaces, logging failures.\"\"\"\n41\t for ws_id, perms in ws_permissions.items():\n42\t try:\n43\t sdk.catalog_permission.put_declarative_permissions(ws_id, perms)\n44\t except Exception as e: # noqa: PERF203\n45\t logger.warning(f\"RESTORE FAILED [permissions for {ws_id}]: {e}\")\n46\t\n47\t\n48\tdef safe_delete(func: Callable, *args: Any, **kwargs: Any) -> None:\n49\t \"\"\"Call a cleanup function, swallowing any exception so it doesn't mask test failures.\n50\t\n51\t Use this in `finally` blocks instead of bare cleanup calls.\n52\t \"\"\"\n53\t try:\n54\t func(*args, **kwa", "truncated": true}]} +{"ts": 1778658251.9786317, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The test `test_layout_ip_allowlist_policies` uses only `@gd_vcr.use_cassette` decorator and `test_config` fixture. It doesn't use snapshot fixtures. Let me check the VCR configuration.", "truncated": false}]} +{"ts": 1778658253.1924894, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01TNM6R6FtYh2s2RzQ1F6FU1", "input": "{\"pattern\": \"**/conftest.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk\"}", "truncated": false}]} +{"ts": 1778658253.562414, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01TNM6R6FtYh2s2RzQ1F6FU1", "is_error": false, "content": "packages/gooddata-sdk/tests/catalog/conftest.py\npackages/gooddata-sdk/tests/conftest.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/pyarrow/conftest.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/pyarrow/tests/conftest.py\npackages/gooddata-sdk/.tox/py312/lib/python3.12/site-packages/pyarrow/tests/parquet/conftest.py", "truncated": false}]} +{"ts": 1778658254.0934076, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01AAeVjxQiN62YjH96GXXKo1", "input": "{\"pattern\": \"gd_vcr\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/test_catalog_organization.py\", \"output_mode\": \"content\", \"head_limit\": 10}", "truncated": false}]} +{"ts": 1778658254.3219137, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01AAeVjxQiN62YjH96GXXKo1", "is_error": false, "content": "23:gd_vcr = get_vcr()\n68:@gd_vcr.use_cassette(str(_fixtures_dir / \"organization.yaml\"))\n75:@gd_vcr.use_cassette(str(_fixtures_dir / \"update_name.yaml\"))\n93:@gd_vcr.use_cassette(str(_fixtures_dir / \"create_jwk.yaml\"))\n106:@gd_vcr.use_cassette(str(_fixtures_dir / \"update_jwk.yaml\"))\n120:@gd_vcr.use_cassette(str(_fixtures_dir / \"delete_jwk.yaml\"))\n134:@gd_vcr.use_cassette(str(_fixtures_dir / \"list_jwk.yaml\"))\n150:@gd_vcr.use_cassette(str(_fixtures_dir / \"create_organization_setting.yaml\"))\n168:@gd_vcr.use_cassette(str(_fixtures_dir / \"list_organization_settings.yaml\"))\n190:@gd_vcr.use_cassette(str(_fixtures_dir / \"delete_organization_setting.yaml\"))\n\n[Showing results with pagination = limit: 10]", "truncated": false}]} +{"ts": 1778658256.498675, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_017RSgPSMJAXmEVJpRPzXnJu", "input": "{\"pattern\": \"**/vcr_utils.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\"}", "truncated": false}]} +{"ts": 1778658256.9184864, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017RSgPSMJAXmEVJpRPzXnJu", "is_error": false, "content": "No files found", "truncated": false}]} +{"ts": 1778658256.9246876, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01Y1kwbyQyAoFFC8YUYhJ18D", "input": "{\"pattern\": \"def get_vcr\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658256.9713993, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01Y1kwbyQyAoFFC8YUYhJ18D", "is_error": false, "content": "transcripts/fix-C009-attempt2.jsonl:72:{\"ts\": 1778658256.9246876, \"type\": \"assistant\", \"blocks\": [{\"type\": \"tool_use\", \"name\": \"Grep\", \"id\": \"toolu_01Y1kwbyQyAoFFC8YUYhJ18D\", \"input\": \"{\\\"pattern\\\": \\\"def get_vcr\\\", \\\"path\\\": \\\"/home/runner/_work/gdc-nas/gdc-nas/sdk\\\", \\\"output_mode\\\": \\\"content\\\"}\", \"truncated\": false}]}\ntranscripts/fix-C009-attempt1.jsonl:96:{\"ts\": 1778657977.2148771, \"type\": \"assistant\", \"blocks\": [{\"type\": \"tool_use\", \"name\": \"Grep\", \"id\": \"toolu_01R2USTzhRSs9TeMxsUQNfa5\", \"input\": \"{\\\"pattern\\\": \\\"def get_vcr|match_on|record_mode\\\", \\\"path\\\": \\\"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests\\\", \\\"output_mode\\\": \\\"content\\\", \\\"head_limit\\\": 30}\", \"truncated\": false}]}\npackages/tests-support/src/tests_support/vcrpy_utils.py:329:def get_vcr() -> vcr.VCR:", "truncated": false}]} +{"ts": 1778658260.2893312, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01XSpMjGiHhEjru6jTAtfFM7", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\", \"offset\": 325, \"limit\": 40}", "truncated": false}]} +{"ts": 1778658260.3942592, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XSpMjGiHhEjru6jTAtfFM7", "is_error": false, "content": "325\tdef _noop_matcher(r1: Any, r2: Any) -> None:\n326\t \"\"\"Always matches \u2014 used to disable scheme/host/port matching across environments.\"\"\"\n327\t\n328\t\n329\tdef get_vcr() -> vcr.VCR:\n330\t gd_vcr = vcr.VCR(\n331\t filter_headers=[\"authorization\", \"user-agent\"],\n332\t match_on=VCR_MATCH_ON,\n333\t before_record_request=custom_before_request,\n334\t before_record_response=custom_before_response,\n335\t decode_compressed_response=True,\n336\t record_mode=RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE,\n337\t )\n338\t gd_vcr.register_matcher(\"body\", _body_matcher)\n339\t # Cassettes recorded against staging must replay in CI (localhost).\n340\t # Disable scheme/host/port matching \u2014 path is sufficient.\n341\t for matcher in (\"scheme\", \"host\", \"port\"):\n342\t gd_vcr.register_matcher(matcher, _noop_matcher)\n343\t\n344\t gd_vcr.register_serializer(\"custom\", CustomSerializerYaml())\n345\t gd_vcr.serializer = \"custom\"\n346\t return gd_vcr\n347\t\n348\t\n349\tdef _stabilize_hash_placeholders(cassette_dict: dict[str, Any]) -> dict[str, str]:\n350\t \"\"\"Build a rename map for hash placeholders based on export format context.\n351\t\n352\t During recording, execution/export hashes get session-global numeric indices\n353\t (EXECUTION_NORMALIZED_3, EXPORT_NORMALIZED_5). These indices shift when test\n354\t execution order changes, causing spurious cassette diffs.\n355\t\n356\t This function scans the cassette for export context (POST /export/tabular with\n357\t a ``format`` field) and returns a mapping from old placeholder names to stable,\n358\t format-based names (e.g. EXECUTION_NORMALIZED_CSV, EXPORT_NORMALIZED_XLSX).\n359\t\n360\t Non-export hashes (pure compute results) are re-indexed per-cassette starting\n361\t from 1.\n362\t \"\"\"\n363\t exec_renames: dict[str, str] = {} # old placeholder \u2192 new name\n364\t export_renames: dict[str, str] = {}", "truncated": false}]} +{"ts": 1778658269.7868629, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the record mode is `ONCE` (unless `OVERWRITE` is in env). In \"ONCE\" mode, VCR.py records the cassette the first time (when it doesn't exist), and plays it back afterwards. In playback mode, if there are no more interactions in the cassette, VCR.py raises a `CannotSendRequest` error (in vcrpy), not a 400 from a live server.\n\nBut the error we're seeing is a real 400 from the live server, not a `CannotSendRequest`. This is strange...\n\n\nActually, the cassette file does exist, and it's returning a real 400 response. That means the cassette has a 400 status recorded for one of the PUT requests in this test. Let me check what's actually stored in the cassette entries.\n\nI'm noticing the cassette has 10 interactions total, with the last PUT request at line 21461, but the test should only be making 6 requests. I need to understand how VCR_MATCH_ON works to see if those extra interactions are being consumed or if there's a mismatch in how requests are being matched.", "truncated": false}]} +{"ts": 1778658269.8061934, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_014oHXhbomFc64cQKWwiEAvg", "input": "{\"pattern\": \"VCR_MATCH_ON\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658269.821447, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_014oHXhbomFc64cQKWwiEAvg", "is_error": false, "content": "16:VCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n332: match_on=VCR_MATCH_ON,", "truncated": false}]} +{"ts": 1778658298.3136282, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So it matches on `method`, `path`, `query`, `body`. This means that each request is matched based on these attributes. If there are multiple matching requests (same method, path, query, body), VCR.py will use the FIRST unplayed one.\n\nFor `set_organization_layout`, the body is the full org layout JSON. So two PUT requests with the same body will both match the same cassette entry. That should work fine.\n\nBut wait - the test is failing with a 400 error. Since VCR.py intercepts requests and plays back cassette responses, the 400 must be IN the cassette as a recorded response.\n \nActually, looking at the error more closely, the request is hitting a real server - the response headers include `X-Gdc-Trace-Id`, which means VCR.py isn't intercepting it. This could happen if the cassette is in ONCE mode and the PUT request body doesn't match any existing cassette entry, causing VCR.py to fall through to a real request. Or the cassette entries have been exhausted and it's allowing fallthrough.\n\nBut wait, there's something I'm missing here. The error message says \"During handling of the above exception\" - there was already an exception before this one. The pytest output we're seeing starts partway through, showing a 400 response with a trace ID. I need to look at the full output to understand what the initial exception was.\n\nLooking more carefully, I can see there are actually TWO different trace IDs in the errors - one ending in `889ab95` from the first exception, and another `ce58692` from a second exception that occurred during cleanup. Both are real 400 responses from the live server, which means both PUT requests are hitting the actual server instead of being matched by the cassette.\n\nLet me trace through what the test is actually doing. It calls `get_declarative_ip_allowlist_policies()` which internally calls `get_organization_layout`, then it calls `put_declarative_ip_allowlist_policies()` with new policies, which also calls `get_organization_layout`. The cassette has 10", "truncated": true}]} +{"ts": 1778658298.32708, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01XmFsctPWXUrbSB5bKzjhC4", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/conftest.py\", \"offset\": 1, \"limit\": 100}", "truncated": false}]} +{"ts": 1778658298.3988633, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01XmFsctPWXUrbSB5bKzjhC4", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\timport logging\n3\timport os\n4\tfrom pathlib import Path\n5\tfrom unittest import mock\n6\t\n7\timport pytest\n8\timport yaml\n9\tfrom gooddata_sdk import GoodDataSdk\n10\tfrom gooddata_sdk.catalog.data_source.service import CatalogDataSourceService\n11\tfrom tests_support.vcrpy_utils import configure_normalization\n12\t\n13\tlogger = logging.getLogger(__name__)\n14\t\n15\t_current_dir = Path(__file__).parent.absolute()\n16\t_credentials_path = _current_dir / \"catalog\" / \"load\" / \"data_source_credentials\" / \"data_sources_credentials.yaml\"\n17\t\n18\t# ---------------------------------------------------------------------------\n19\t# Failure tracker \u2014 used by session snapshot to decide whether to restore\n20\t# ---------------------------------------------------------------------------\n21\t_session_has_failures = False\n22\t\n23\t\n24\tdef pytest_runtest_makereport(item, call):\n25\t \"\"\"Track whether any test has failed during the session.\"\"\"\n26\t global _session_has_failures\n27\t if call.excinfo is not None:\n28\t _session_has_failures = True\n29\t\n30\t\n31\tdef pytest_addoption(parser):\n32\t default_config_path = Path(__file__).parent / \"gd_test_config.yaml\"\n33\t parser.addoption(\n34\t \"--gd-test-config\",\n35\t action=\"store\",\n36\t default=str(default_config_path),\n37\t help=\"Path to test configuration file\",\n38\t )\n39\t\n40\t\n41\t@pytest.fixture(scope=\"session\")\n42\tdef test_config(request):\n43\t config_path = Path(request.config.getoption(\"--gd-test-config\"))\n44\t with open(config_path) as f:\n45\t config = yaml.safe_load(f)\n46\t\n47\t # Merge environment-specific overrides into top-level config\n48\t env_name = os.environ.get(\"GD_TEST_ENV\", \"local\")\n49\t environments = config.pop(\"environments\", {})\n50\t if env_name in environments:\n51\t config.update(environments[env_name])\n52\t\n53\t # Override secrets from env vars (staging CI passes these)\n54\t env_token = os.environ.get(\"TOKEN\")\n55\t if env_token:\n56\t co", "truncated": true}]} +{"ts": 1778658301.0169902, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "I now see that VCR.py is set to `RecordMode.ONCE`, which means it plays back if the cassette exists. But the test is actually making real HTTP requests to the staging server. This is strange.\n\nActually, let me look at `configure_normalization` and check if there's a mode where VCR might be bypassed when running against staging:", "truncated": false}]} +{"ts": 1778658301.8107648, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_011FHvLeTGU9nzt51rHEoCy9", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\", \"offset\": 1, \"limit\": 80}", "truncated": false}]} +{"ts": 1778658301.841822, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011FHvLeTGU9nzt51rHEoCy9", "is_error": false, "content": "1\t# (C) 2022 GoodData Corporation\n2\tfrom __future__ import annotations\n3\t\n4\timport os\n5\timport re\n6\timport typing\n7\timport xml.etree.ElementTree as ET\n8\tfrom typing import Any\n9\tfrom urllib.parse import urlparse\n10\t\n11\timport orjson\n12\timport vcr\n13\timport yaml\n14\tfrom vcr.record_mode import RecordMode\n15\t\n16\tVCR_MATCH_ON = (\"method\", \"path\", \"query\", \"body\")\n17\tNON_STATIC_HEADERS = [\"DATE\", \"X-GDC-CANCEL-TOKEN\", \"X-GDC-TRACE-ID\"]\n18\t\n19\t# Infrastructure headers injected by reverse proxies / load balancers.\n20\t# These differ between local and staging and are irrelevant to API behavior.\n21\t_STRIPPED_RESPONSE_HEADERS = {\n22\t \"X-Xss-Protection\",\n23\t \"Strict-Transport-Security\",\n24\t \"Vary\",\n25\t \"Content-Encoding\",\n26\t \"Content-Length\",\n27\t \"Transfer-Encoding\",\n28\t \"Referrer-Policy\",\n29\t \"Cache-Control\",\n30\t}\n31\tHEADERS_STR = \"headers\"\n32\tPLACEHOLDER = [\"PLACEHOLDER\"]\n33\t\n34\t# Fields stripped from request bodies before VCR body matching.\n35\t# These differ between local and staging environments but don't affect\n36\t# the logical identity of a request.\n37\t_ENV_SPECIFIC_BODY_FIELDS = {\n38\t \"password\",\n39\t \"token\",\n40\t \"url\",\n41\t \"username\",\n42\t \"privateKey\",\n43\t \"client_secret\",\n44\t \"private_key_passphrase\",\n45\t}\n46\t\n47\t# Canonical (local) values \u2014 cassettes always use these.\n48\t_CANONICAL_HOST = \"http://localhost:3000\"\n49\t_CANONICAL_HOSTNAME = \"localhost\"\n50\t_CANONICAL_ORG_ID = \"default\"\n51\t_CANONICAL_ORG_NAME = \"Default Organization\"\n52\t_CANONICAL_DS_URL = \"jdbc:postgresql://postgres:5432/tiger?sslmode=prefer\"\n53\t_CANONICAL_DS_PASSWORD = \"passw0rd\"\n54\t\n55\t# Module-level normalization state.\n56\t# Populated by configure_normalization() before tests run.\n57\t# Each entry is (source_string, replacement_string).\n58\t# Ordered longest-first so more specific patterns match before substrings.\n59\t_normalization_replacements: list[tuple[str, str]] = []\n60\t_password_replacements: list[tuple[re.Pattern, str]] = []\n61\t_normalization_configured", "truncated": true}]} +{"ts": 1778658304.1183975, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01DVFMwSgYFkoewDZi4Ab9E5", "input": "{\"pattern\": \"RecordMode|OVERWRITE|record_mode|staging\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658304.1501255, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01DVFMwSgYFkoewDZi4Ab9E5", "is_error": false, "content": "14:from vcr.record_mode import RecordMode\n20:# These differ between local and staging and are irrelevant to API behavior.\n35:# These differ between local and staging environments but don't affect\n215: # Full origin URL: \"https://staging.example.com\" \u2192 \"http://localhost:3000\"\n220: # from the bare hostname): \"staging.example.com:8443\" \u2192 \"localhost:3000\"\n228: # Bare hostname: \"staging.example.com\" \u2192 \"localhost\"\n240: # Data source JDBC URL: staging DB host/name \u2192 local DB host/name\n250: # Data source password: staging password \u2192 local password\n336: record_mode=RecordMode.ALL if \"OVERWRITE\" in os.environ else RecordMode.ONCE,\n339: # Cassettes recorded against staging must replay in CI (localhost).\n588: if not _normalization_configured and \"OVERWRITE\" in os.environ:\n625: if not _normalization_configured and \"OVERWRITE\" in os.environ:", "truncated": false}]} +{"ts": 1778658312.1328156, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "OK, so the VCR mode is:\n- `RecordMode.ALL` if `OVERWRITE` env var is set (rerecords everything)\n- `RecordMode.ONCE` otherwise (plays back cassette if exists, records if not)\n\nThe cassette exists, so the test is in playback mode. This means VCR.py is intercepting requests and playing back responses from the cassette.\n\nBut then how is it getting a REAL 400 response from the server with a real `X-Gdc-Trace-Id`?!\n\nUnless... the cassette doesn't have a matching entry for the specific PUT request, and in `ONCE` mode, VCR makes a real network call for unmatched requests (rather than raising an error). Let me verify this VCR behavior.\n\n\nActually, checking the VCR.py docs, `ONCE` mode should raise `CannotSendRequest` if a request doesn't match anything in the cassette during replay. So that's not it. The vcrpy version might behave differently, or maybe the issue is with how `_body_matcher` is matching requests.", "truncated": false}]} +{"ts": 1778658312.1405597, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01HLR9CfNZ5WuQskn8bnN1n7", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/tests-support/src/tests_support/vcrpy_utils.py\", \"offset\": 280, \"limit\": 50}", "truncated": false}]} +{"ts": 1778658312.1698356, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HLR9CfNZ5WuQskn8bnN1n7", "is_error": false, "content": "280\t \"\"\"Replace transient server values with deterministic placeholders.\"\"\"\n281\t text = _EXEC_HASH_BODY_RE.sub(_exec_hash_replacer, text)\n282\t text = _EXPORT_HASH_BODY_RE.sub(_export_hash_replacer, text)\n283\t text = _CREATED_AT_RE.sub(_CANONICAL_CREATED_AT, text)\n284\t text = _TRACE_ID_RE.sub(_CANONICAL_TRACE_ID, text)\n285\t text = _AUTH_ID_RE.sub(_CANONICAL_AUTH_ID, text)\n286\t text = _BEARER_TOKEN_RE.sub(_CANONICAL_BEARER_TOKEN, text)\n287\t text = _CACHE_ID_RE.sub(_CANONICAL_CACHE_ID, text)\n288\t text = _QUERY_DURATION_RE.sub(\"0\", text)\n289\t return text\n290\t\n291\t\n292\tdef _normalize_hashes_in_uri(uri: str) -> str:\n293\t \"\"\"Replace executionResult/exportResult hashes in a request URI.\"\"\"\n294\t uri = _EXEC_HASH_URI_RE.sub(_exec_hash_replacer, uri)\n295\t uri = _EXPORT_HASH_URI_RE.sub(_export_hash_replacer, uri)\n296\t return uri\n297\t\n298\t\n299\tdef _normalize_body(body: str | None) -> str:\n300\t \"\"\"Strip environment-specific fields from a JSON request body for matching.\"\"\"\n301\t if not body:\n302\t return body or \"\"\n303\t try:\n304\t data = orjson.loads(body)\n305\t except (orjson.JSONDecodeError, TypeError):\n306\t return body\n307\t\n308\t def _strip(obj: Any) -> Any:\n309\t if isinstance(obj, dict):\n310\t return {k: _strip(v) for k, v in obj.items() if k not in _ENV_SPECIFIC_BODY_FIELDS}\n311\t if isinstance(obj, list):\n312\t return [_strip(item) for item in obj]\n313\t return obj\n314\t\n315\t return orjson.dumps(_strip(data), option=orjson.OPT_SORT_KEYS).decode(\"utf-8\")\n316\t\n317\t\n318\tdef _body_matcher(r1: Any, r2: Any) -> None:\n319\t \"\"\"Custom VCR body matcher that ignores environment-specific fields.\"\"\"\n320\t b1 = _normalize_body(r1.body)\n321\t b2 = _normalize_body(r2.body)\n322\t assert b1 == b2, f\"Request bodies differ after normalization:\\n{b1}\\n!=\\n{b2}\"\n323\t\n324\t\n325\tdef _noop_matcher(r1: Any, r2: Any) -> None:\n326\t \"\"\"Always matches \u2014 used to disable scheme/host/", "truncated": true}]} +{"ts": 1778658322.7483032, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I see! The body matcher strips environment-specific fields (`password`, `token`, `url`, `username`, etc.) before comparing. So when comparing PUT request bodies, these fields are stripped.\n\nNow, looking at the error: the cassette has an interaction for a PUT to `/api/v1/layout/organization` that contains a 400 response with the message \"Invalid combination of auth properties\". This means the cassette WAS recorded when the PUT was made with an incomplete datasource credentials. \n\nWait... that doesn't make sense. If the cassette was recorded with a successful PUT (200 response) but now the PUT fails with a 400, that would mean the cassette has different content.\n \nActually, I'm looking at the error more carefully. The response headers like `X-Xss-Protection`, `Strict-Transport-Security`, and `Vary` are being stripped during comparison, so those shouldn't be causing a mismatch.\n\nWait, I'm realizing something important here. These headers are showing up in the actual error output, which means this is a real HTTP response, not a cassette playback at all. The VCR interception isn't working for this request. Let me check the cassette file around the PUT request to see what was actually recorded versus what's being sent now.", "truncated": false}]} +{"ts": 1778658322.7898874, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01FNDibJ4pRGV8mRtpz8kWEX", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6425, \"limit\": 60}", "truncated": false}]} +{"ts": 1778658322.841283, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01FNDibJ4pRGV8mRtpz8kWEX", "is_error": false, "content": "6425\t method: PUT\n6426\t uri: http://localhost:3000/api/v1/layout/organization\n6427\t response:\n6428\t body:\n6429\t string:\n6430\t detail: 'Invalid combination of auth properties. Only none, user + password,\n6431\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n6432\t user: , password: , token: , key-pair: , clientId: ,\n6433\t clientSecret: '\n6434\t status: 400\n6435\t title: Bad Request\n6436\t traceId: NORMALIZED_TRACE_ID_000000000000\n6437\t headers:\n6438\t Content-Type:\n6439\t - application/problem+json\n6440\t DATE: *id001\n6441\t Expires:\n6442\t - '0'\n6443\t Pragma:\n6444\t - no-cache\n6445\t X-Content-Type-Options:\n6446\t - nosniff\n6447\t X-GDC-TRACE-ID: *id001\n6448\t status:\n6449\t code: 400\n6450\t message: Bad Request\n6451\t - request:\n6452\t body: null\n6453\t headers:\n6454\t Accept:\n6455\t - application/json\n6456\t Accept-Encoding:\n6457\t - br, gzip, deflate\n6458\t X-GDC-VALIDATE-RELATIONS:\n6459\t - 'true'\n6460\t X-Requested-With:\n6461\t - XMLHttpRequest\n6462\t method: GET\n6463\t uri: http://localhost:3000/api/v1/layout/organization\n6464\t response:\n6465\t body:\n6466\t string:\n6467\t agents:\n6468\t - aiKnowledge: true\n6469\t availableToAll: true\n6470\t enabled: true\n6471\t id: default-ai-assistant\n6472\t name: Default GoodData AI Assistant\n6473\t skillsMode: all\n6474\t customGeoCollections: []\n6475\t dataSources:\n6476\t - alternativeDataSourceId: ds-put-abc-id\n6477\t authenticationType: USERNAME_PASSWORD\n6478\t id: demo-test-ds\n6479\t name: demo-test-ds\n6480\t permissions:\n6481\t - assignee:\n6482", "truncated": true}]} +{"ts": 1778658343.214608, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Now I understand! The cassette itself has a recorded 400 response for the first PUT request! And then it records the next GET (after the 400), and then possibly retrying...\n\nWait, looking at the cassette structure:\n- GET (line 13) - initial get\n- GET (line 2158) - second get (from inside put method for reading org layout)\n- PUT (line 6425) - with 400 response!\n- GET (line 6462) - get after the 400 PUT\n- PUT (line 10719) - another PUT\n\n\n- GET (line 10756)\n- GET (line 12900)\n- PUT (line 17167)\n- GET (line 17204)\n- PUT (line 21461)\n\nSo the cassette was recorded when the test was actually failing with a 400 error. Since it's in ONCE mode and the cassette exists, it's replaying those recorded responses, but the 400 triggers an exception that sends the test into the except/finally block, which then tries to make real HTTP requests instead of using the cassette.\n\nBut wait, the actual error output shows real HTTP requests are being made\u2014the response headers in the pytest output include `Vary`, `X-Xss-Protection`, and `Strict-Transport-Security`, which aren't present in the cassette. This means VCR isn't intercepting these requests at all, they're hitting a real staging server. Let me figure out why VCR isn't catching them.\n\nLooking at the cassette entry for the PUT request, the body field is null, but the actual request being sent has a JSON body with the org layout content. Since the body doesn't match what's recorded in the cassette, VCR can't find a matching entry and falls through to making a real HTTP request instead. So when the body matcher fails with an AssertionError, vcrpy treats that cassette entry as non-matching and moves to the next one. If no entries match, it should raise `CannotSendRequest`, but we're seeing actual HTTP requests go through instead\u2014which suggests something else is happening with how the matcher is being applied or the cassette is being configured. Let me look more closely at what's actually in the PUT request body within the cassette.", "truncated": false}]} +{"ts": 1778658343.2363448, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01CEowbgTcqRNbQJWJgmke3t", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 6400, \"limit\": 30}", "truncated": false}]} +{"ts": 1778658343.2517872, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CEowbgTcqRNbQJWJgmke3t", "is_error": false, "content": "6400\t exportDefinitions: []\n6401\t filterContexts: []\n6402\t memoryItems: []\n6403\t metrics: []\n6404\t parameters: []\n6405\t visualizationObjects: []\n6406\t ldm:\n6407\t datasets: []\n6408\t dateInstances: []\n6409\t name: Demo West California\n6410\t parent:\n6411\t id: demo_west\n6412\t type: workspace\n6413\t permissions: []\n6414\t settings: []\n6415\t userDataFilters: []\n6416\t headers:\n6417\t Accept-Encoding:\n6418\t - br, gzip, deflate\n6419\t Content-Type:\n6420\t - application/json\n6421\t X-GDC-VALIDATE-RELATIONS:\n6422\t - 'true'\n6423\t X-Requested-With:\n6424\t - XMLHttpRequest\n6425\t method: PUT\n6426\t uri: http://localhost:3000/api/v1/layout/organization\n6427\t response:\n6428\t body:\n6429\t string:", "truncated": false}]} +{"ts": 1778658345.0951164, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look further back to see the full PUT request, including the body.", "truncated": false}]} +{"ts": 1778658345.7388573, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01QgJDhE7EeuHoRQC2ipccpu", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 2155, \"limit\": 30}", "truncated": false}]} +{"ts": 1778658345.7862532, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01QgJDhE7EeuHoRQC2ipccpu", "is_error": false, "content": "2155\t - 'true'\n2156\t X-Requested-With:\n2157\t - XMLHttpRequest\n2158\t method: GET\n2159\t uri: http://localhost:3000/api/v1/layout/organization\n2160\t response:\n2161\t body:\n2162\t string:\n2163\t agents:\n2164\t - aiKnowledge: true\n2165\t availableToAll: true\n2166\t enabled: true\n2167\t id: default-ai-assistant\n2168\t name: Default GoodData AI Assistant\n2169\t skillsMode: all\n2170\t customGeoCollections: []\n2171\t dataSources:\n2172\t - alternativeDataSourceId: ds-put-abc-id\n2173\t authenticationType: USERNAME_PASSWORD\n2174\t id: demo-test-ds\n2175\t name: demo-test-ds\n2176\t permissions:\n2177\t - assignee:\n2178\t id: demo2\n2179\t type: user\n2180\t name: MANAGE\n2181\t - assignee:\n2182\t id: demoGroup\n2183\t type: userGroup\n2184\t name: USE", "truncated": false}]} +{"ts": 1778658348.1601665, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01VUiMu2rrKMQuXGzT9oenfZ", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 2140, \"limit\": 20}", "truncated": false}]} +{"ts": 1778658348.200517, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01VUiMu2rrKMQuXGzT9oenfZ", "is_error": false, "content": "2140\t - no-cache\n2141\t X-Content-Type-Options:\n2142\t - nosniff\n2143\t X-GDC-TRACE-ID: *id001\n2144\t status:\n2145\t code: 200\n2146\t message: OK\n2147\t - request:\n2148\t body: null\n2149\t headers:\n2150\t Accept:\n2151\t - application/json\n2152\t Accept-Encoding:\n2153\t - br, gzip, deflate\n2154\t X-GDC-VALIDATE-RELATIONS:\n2155\t - 'true'\n2156\t X-Requested-With:\n2157\t - XMLHttpRequest\n2158\t method: GET\n2159\t uri: http://localhost:3000/api/v1/layout/organization", "truncated": false}]} +{"ts": 1778658350.4898698, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The second GET request has `body: null`. Let me look for where the PUT request body starts - I need to look backwards from line 6425 to find the `body:` key.", "truncated": false}]} +{"ts": 1778658351.2334259, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01E44YQkJj91q93axY4HFsTB", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 2147, \"limit\": 30}", "truncated": false}]} +{"ts": 1778658351.2797103, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01E44YQkJj91q93axY4HFsTB", "is_error": false, "content": "2147\t - request:\n2148\t body: null\n2149\t headers:\n2150\t Accept:\n2151\t - application/json\n2152\t Accept-Encoding:\n2153\t - br, gzip, deflate\n2154\t X-GDC-VALIDATE-RELATIONS:\n2155\t - 'true'\n2156\t X-Requested-With:\n2157\t - XMLHttpRequest\n2158\t method: GET\n2159\t uri: http://localhost:3000/api/v1/layout/organization\n2160\t response:\n2161\t body:\n2162\t string:\n2163\t agents:\n2164\t - aiKnowledge: true\n2165\t availableToAll: true\n2166\t enabled: true\n2167\t id: default-ai-assistant\n2168\t name: Default GoodData AI Assistant\n2169\t skillsMode: all\n2170\t customGeoCollections: []\n2171\t dataSources:\n2172\t - alternativeDataSourceId: ds-put-abc-id\n2173\t authenticationType: USERNAME_PASSWORD\n2174\t id: demo-test-ds\n2175\t name: demo-test-ds\n2176\t permissions:", "truncated": false}]} +{"ts": 1778658353.77851, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look at the structure right before line 6425 (the PUT) more carefully. Let me look at where the PUT request body starts:", "truncated": false}]} +{"ts": 1778658354.3081646, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01HcR5Xqy7CHNATHcko3jQGP", "input": "{\"pattern\": \"- request:\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658354.3452504, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01HcR5Xqy7CHNATHcko3jQGP", "is_error": false, "content": "2: - request:\n2147: - request:\n4291: - request:\n6451: - request:\n8595: - request:\n10745: - request:\n12889: - request:\n15033: - request:\n17193: - request:\n19337: - request:", "truncated": false}]} +{"ts": 1778658363.2770407, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So there are 10 request/response pairs in the cassette:\n1. Lines 2-2146 (request at 2, GET)\n2. Lines 2147-4290 (request at 2147, GET)\n3. Lines 4291-6450 (request at 4291, PUT - response is 400)\n4. Lines 6451-8594 (request at 6451, GET)\n5. Lines 8595-10744 (request at 8595, PUT)\n\n\n6. Lines 10745-12888 (request at 10745, GET)\n7. Lines 12889-15032 (request at 12889, GET)\n8. Lines 15033-17192 (request at 15033, PUT)\n9. Lines 17193-19336 (request at 17193, GET)\n10. Lines 19337-end (request at 19337, PUT)\n\nBut I'm noticing some inconsistencies with the PUT method markers I spotted earlier at lines 6425, 10719, 17167, and 21461. Let me recheck the actual request indices to make sure my boundaries are correct.\n\nLooking at where each request actually starts:\n- Line 2, 2147, 4291, 6451, 8595, 10745, 12889, 15033, 17193, 19337\n\nAnd cross-referencing with the method and URI lines:\n- Line 13: GET\n- Line 2158: GET\n- Line 6425: PUT\n- Line 6462: GET\n- Line 10719: PUT\n- Line 10756: GET\n- Line 12900: GET\n- Line 17167: PUT\n- Line 17204: GET\n- Line 21461: PUT\n\nThe discrepancy is coming from the fact that PUT request bodies span multiple lines before the method declaration appears. Let me trace through what's happening at line 4291 to understand the pattern better.", "truncated": false}]} +{"ts": 1778658363.2917686, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_017c7Mxu7KAPKsoXJAfUTdg2", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 4291, \"limit\": 15}", "truncated": false}]} +{"ts": 1778658363.324055, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_017c7Mxu7KAPKsoXJAfUTdg2", "is_error": false, "content": "4291\t - request:\n4292\t body:\n4293\t agents:\n4294\t - aiKnowledge: true\n4295\t availableToAll: true\n4296\t enabled: true\n4297\t id: default-ai-assistant\n4298\t name: Default GoodData AI Assistant\n4299\t skillsMode: all\n4300\t customGeoCollections: []\n4301\t dataSources:\n4302\t - alternativeDataSourceId: ds-put-abc-id\n4303\t authenticationType: USERNAME_PASSWORD\n4304\t id: demo-test-ds\n4305\t name: demo-test-ds", "truncated": false}]} +{"ts": 1778658393.9892564, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "The request body for the PUT at line 4291 is the full organization layout JSON. So the cassette DOES have the request body for the PUT.\n\nNow, the response for this PUT is a 400. And looking at the cassette interaction structure:\n1. GET (request at 2) \n2. GET (request at 2147)\n3. PUT (request at 4291, response is 400 at lines 6425-6450)\n4. GET (request at 6451)\n\n\n5. PUT (request at 8595)\n6. GET (request at 10745)\n7. GET (request at 12889)\n8. PUT (request at 15033)\n9. GET (request at 17193)\n10. PUT (request at 19337)\n\nSo there are 3 GETs and 4 PUTs total, with the first PUT failing with a 400 error. This looks like a test that was recorded mid-execution and stopped partway through, likely after encountering that initial failure.\n\nNow I'm mapping out the actual test flow. The test starts by fetching the original policies, then attempts to update with new ones (which fails with 400), and in the finally block it restores the original policies. The sequence shows a GET to fetch the current state, a PUT that returns 400 due to auth issues, then another GET inside the finally block to retrieve the original policies again before restoring them.\n\nBut wait\u2014looking at the cassette more carefully, there are more interactions recorded than what the current code structure would produce. This suggests the implementation might have changed since the cassette was recorded. If the `put_declarative_ip_allowlist_policies` method originally didn't perform an internal read-modify-write operation, the cassette would show just four interactions: an initial GET, a PUT, a GET to verify the result, and a final PUT to restore the original state\u2014without any extra GETs nested inside the PUT calls.\n\nThe real issue is that the cassette has a 400 response recorded for the first PUT request, which happened because the test was run against staging with a malformed request body\u2014the datasource had a username but no password. To fix this, I need to correct the request payload so it's valid. to make `put_", "truncated": true}]} +{"ts": 1778658394.0010993, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01ToPLs2YPaAzpAXQUd3KV3J", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 8595, \"limit\": 20}", "truncated": false}]} +{"ts": 1778658394.0277512, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01ToPLs2YPaAzpAXQUd3KV3J", "is_error": false, "content": "8595\t - request:\n8596\t body:\n8597\t agents:\n8598\t - aiKnowledge: true\n8599\t availableToAll: true\n8600\t enabled: true\n8601\t id: default-ai-assistant\n8602\t name: Default GoodData AI Assistant\n8603\t skillsMode: all\n8604\t customGeoCollections: []\n8605\t dataSources:\n8606\t - alternativeDataSourceId: ds-put-abc-id\n8607\t authenticationType: USERNAME_PASSWORD\n8608\t id: demo-test-ds\n8609\t name: demo-test-ds\n8610\t permissions:\n8611\t - assignee:\n8612\t id: demo2\n8613\t type: user\n8614\t name: MANAGE", "truncated": false}]} +{"ts": 1778658396.0471694, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01NMDTuAQGsqUNMSM2JirdsT", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 10719, \"limit\": 30}", "truncated": false}]} +{"ts": 1778658396.0786192, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01NMDTuAQGsqUNMSM2JirdsT", "is_error": false, "content": "10719\t method: PUT\n10720\t uri: http://localhost:3000/api/v1/layout/organization\n10721\t response:\n10722\t body:\n10723\t string:\n10724\t detail: 'Invalid combination of auth properties. Only none, user + password,\n10725\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n10726\t user: , password: , token: , key-pair: , clientId: ,\n10727\t clientSecret: '\n10728\t status: 400\n10729\t title: Bad Request\n10730\t traceId: NORMALIZED_TRACE_ID_000000000000\n10731\t headers:\n10732\t Content-Type:\n10733\t - application/problem+json\n10734\t DATE: *id001\n10735\t Expires:\n10736\t - '0'\n10737\t Pragma:\n10738\t - no-cache\n10739\t X-Content-Type-Options:\n10740\t - nosniff\n10741\t X-GDC-TRACE-ID: *id001\n10742\t status:\n10743\t code: 400\n10744\t message: Bad Request\n10745\t - request:\n10746\t body: null\n10747\t headers:\n10748\t Accept:", "truncated": false}]} +{"ts": 1778658399.4231002, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "So the cassette has TWO 400 responses! Both PUT requests #3 (line 4291) and #5 (line 8595) return 400 errors.\n\nNow let me look at interactions 6, 7, 8, 9, 10 (the GET at 10745, GET at 12889, PUT at 15033, GET at 17193, PUT at 19337).", "truncated": false}]} +{"ts": 1778658400.1312182, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_015akJNWc8FQ8m8JMCkkW7W3", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 15033, \"limit\": 10}", "truncated": false}]} +{"ts": 1778658400.1353521, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_015akJNWc8FQ8m8JMCkkW7W3", "is_error": false, "content": "15033\t - request:\n15034\t body:\n15035\t agents:\n15036\t - aiKnowledge: true\n15037\t availableToAll: true\n15038\t enabled: true\n15039\t id: default-ai-assistant\n15040\t name: Default GoodData AI Assistant\n15041\t skillsMode: all\n15042\t customGeoCollections: []", "truncated": false}]} +{"ts": 1778658400.7599125, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01CEkgYLpsarH7Sw4DQpugns", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/packages/gooddata-sdk/tests/catalog/fixtures/organization/layout_ip_allowlist_policies.yaml\", \"offset\": 17167, \"limit\": 30}", "truncated": false}]} +{"ts": 1778658400.7972205, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01CEkgYLpsarH7Sw4DQpugns", "is_error": false, "content": "17167\t method: PUT\n17168\t uri: http://localhost:3000/api/v1/layout/organization\n17169\t response:\n17170\t body:\n17171\t string:\n17172\t detail: 'Invalid combination of auth properties. Only none, user + password,\n17173\t token, key-pair or client id + secret are allowed. Datasource: demo-test-ds,\n17174\t user: , password: , token: , key-pair: , clientId: ,\n17175\t clientSecret: '\n17176\t status: 400\n17177\t title: Bad Request\n17178\t traceId: NORMALIZED_TRACE_ID_000000000000\n17179\t headers:\n17180\t Content-Type:\n17181\t - application/problem+json\n17182\t DATE: *id001\n17183\t Expires:\n17184\t - '0'\n17185\t Pragma:\n17186\t - no-cache\n17187\t X-Content-Type-Options:\n17188\t - nosniff\n17189\t X-GDC-TRACE-ID: *id001\n17190\t status:\n17191\t code: 400\n17192\t message: Bad Request\n17193\t - request:\n17194\t body: null\n17195\t headers:\n17196\t Accept:", "truncated": false}]} +{"ts": 1778658413.8071806, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "All PUT responses are 400! So the cassette was recorded when ALL PUTs were failing with 400. The cassette captures this failure state.\n\nThis means the cassette itself is broken - it was recorded from a failing test run where all `set_organization_layout` calls were returning 400 errors. But the cassette still exists and hasn't been deleted (it contains content, even though all the content is failure responses).\n\nThe instructions say: \"Do NOT fabricate cassette YAML files \u2014 they will be re-recorded by the pipeline after you finish. Stale cassettes were already deleted (see below).\"\n\nBut this cassette is NOT stale (not deleted) - it's present but has broken content. \n\nSo the real issue is that `put_declarative_ip_allowlist_policies` uses a read-modify-write pattern with `set_organization_layout` that loses datasource passwords, and deleting the cassette won't help since the test would just fail again against the live server with the same bug.\n\nThe core problem is that getting the org layout doesn't return datasource passwords, so when you PUT it back with those missing credentials, the API rejects it. I need to find either a dedicated IP allowlist endpoint, or figure out how to update just that part of the layout without touching the datasource auth fields. Let me search through the available APIs to see if there's a more targeted endpoint for this.", "truncated": false}]} +{"ts": 1778658413.8369935, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Glob", "id": "toolu_01VzAnLk8bomy3sMjx2RTFig", "input": "{\"pattern\": \"**/*api*.py\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api\"}", "truncated": false}]} +{"ts": 1778658413.867863, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01VzAnLk8bomy3sMjx2RTFig", "is_error": false, "content": "gooddata-api-client/gooddata_api_client/api/actions_api.py\ngooddata-api-client/gooddata_api_client/api/agent_controller_api.py\ngooddata-api-client/gooddata_api_client/api/aggregated_fact_controller_api.py\ngooddata-api-client/gooddata_api_client/api/ai_agents_api.py\ngooddata-api-client/gooddata_api_client/api/ai_api.py\ngooddata-api-client/gooddata_api_client/api/ai_lake_api.py\ngooddata-api-client/gooddata_api_client/api/ai_lake_databases_api.py\ngooddata-api-client/gooddata_api_client/api/ai_lake_pipe_tables_api.py\ngooddata-api-client/gooddata_api_client/api/ai_lake_services_operations_api.py\ngooddata-api-client/gooddata_api_client/api/analytical_dashboard_controller_api.py\ngooddata-api-client/gooddata_api_client/api/analytics_model_api.py\ngooddata-api-client/gooddata_api_client/api/api_token_controller_api.py\ngooddata-api-client/gooddata_api_client/api/api_tokens_api.py\ngooddata-api-client/gooddata_api_client/api/appearance_api.py\ngooddata-api-client/gooddata_api_client/api/attribute_controller_api.py\ngooddata-api-client/gooddata_api_client/api/attribute_hierarchies_api.py\ngooddata-api-client/gooddata_api_client/api/attribute_hierarchy_controller_api.py\ngooddata-api-client/gooddata_api_client/api/attributes_api.py\ngooddata-api-client/gooddata_api_client/api/authentication_api.py\ngooddata-api-client/gooddata_api_client/api/automation_controller_api.py\ngooddata-api-client/gooddata_api_client/api/automation_organization_view_controller_api.py\ngooddata-api-client/gooddata_api_client/api/automation_result_controller_api.py\ngooddata-api-client/gooddata_api_client/api/automations_api.py\ngooddata-api-client/gooddata_api_client/api/available_drivers_api.py\ngooddata-api-client/gooddata_api_client/api/cache_usage_api.py\ngooddata-api-client/gooddata_api_client/api/certification_api.py\ngooddata-api-client/gooddata_api_client/api/color_palette_controller_api.py\ngooddata-api-client/gooddata_api_client/api/computation_api.py\ngooddata-api-client/gooddata_api_client/api/cookie_securit", "truncated": true}]} +{"ts": 1778658419.2907581, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_011Kqe7U112Ppx32Beuids29", "input": "{\"pattern\": \"ip_allowlist\\\\|allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/organization_declarative_apis_api.py\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} +{"ts": 1778658419.4668484, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_011Kqe7U112Ppx32Beuids29", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778658419.9507258, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01J3f5ackPHGvCWXgkrSegnC", "input": "{\"pattern\": \"ip_allowlist\\\\|allowlist\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\", \"head_limit\": 20}", "truncated": false}]} +{"ts": 1778658419.993418, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01J3f5ackPHGvCWXgkrSegnC", "is_error": false, "content": "No matches found", "truncated": false}]} +{"ts": 1778658427.7390513, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "There's no dedicated `ip_allowlist` endpoint in the layout API. So the approach of using `set_organization_layout` is the only way. But the problem is that `set_organization_layout` requires proper datasource credentials.\n\nNow, let me think about a different fix. The issue is that when we read the org layout, the datasource username is returned but the password is not. When we write it back, the API rejects \"username without password\".\n\nPossible fixes:\n1. Remove the datasource credential fields from the layout before PUT (set `username = None` for datasources that have username but no password)\n\n\n2. Remove the entire datasource section before PUT (not a good idea - would delete datasources)\n3. Use a different approach that doesn't require the full credentials\n\nI notice that `put_declarative_data_sources` handles this by using a credentials file to supply passwords during updates, but `set_organization_layout` doesn't have that option. Let me check what happens when `set_organization_layout` processes datasource credentials.", "truncated": false}]} +{"ts": 1778658427.7478237, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_01KhucV8K9dxeK6Bm9zdnx8v", "input": "{\"pattern\": \"def set_organization_layout\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"output_mode\": \"content\"}", "truncated": false}]} +{"ts": 1778658427.7742152, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01KhucV8K9dxeK6Bm9zdnx8v", "is_error": false, "content": "5870: def set_organization_layout(", "truncated": false}]} +{"ts": 1778658430.050673, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Read", "id": "toolu_01KLDpSo52FDNZKjmzUa5EzL", "input": "{\"file_path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/api/layout_api.py\", \"offset\": 5870, \"limit\": 90}", "truncated": false}]} +{"ts": 1778658430.1035178, "type": "user", "blocks": [{"type": "tool_result", "tool_use_id": "toolu_01KLDpSo52FDNZKjmzUa5EzL", "is_error": false, "content": "5870\t def set_organization_layout(\n5871\t self,\n5872\t declarative_organization,\n5873\t **kwargs\n5874\t ):\n5875\t \"\"\"Set organization layout # noqa: E501\n5876\t\n5877\t Sets complete layout of organization, like workspaces, user-groups, etc. # noqa: E501\n5878\t This method makes a synchronous HTTP request by default. To make an\n5879\t asynchronous HTTP request, please pass async_req=True\n5880\t\n5881\t >>> thread = api.set_organization_layout(declarative_organization, async_req=True)\n5882\t >>> result = thread.get()\n5883\t\n5884\t Args:\n5885\t declarative_organization (DeclarativeOrganization):\n5886\t\n5887\t Keyword Args:\n5888\t _return_http_data_only (bool): response data without head status\n5889\t code and headers. Default is True.\n5890\t _preload_content (bool): if False, the urllib3.HTTPResponse object\n5891\t will be returned without reading/decoding response data.\n5892\t Default is True.\n5893\t _request_timeout (int/float/tuple): timeout setting for this request. If\n5894\t one number provided, it will be total request timeout. It can also\n5895\t be a pair (tuple) of (connection, read) timeouts.\n5896\t Default is None.\n5897\t _check_input_type (bool): specifies if type checking\n5898\t should be done one the data sent to the server.\n5899\t Default is True.\n5900\t _check_return_type (bool): specifies if type checking\n5901\t should be done one the data received from the server.\n5902\t Default is True.\n5903\t _spec_property_naming (bool): True if the variable names in the input data\n5904\t are serialized names, as specified in the OpenAPI document.\n5905\t False if the variable names in the input data\n5906\t are pythonic names, e.g. snake case (default)\n5", "truncated": true}]} +{"ts": 1778658440.2209585, "type": "assistant", "blocks": [{"type": "thinking", "thinking": "Let me look at the `DeclarativeOrganization` model to understand what fields are there for data sources, and whether we can clear credentials.", "truncated": false}]} +{"ts": 1778658440.9255314, "type": "assistant", "blocks": [{"type": "tool_use", "name": "Grep", "id": "toolu_015KLusPLym8PCSLExxAH5TC", "input": "{\"pattern\": \"class DeclarativeOrganization\", \"path\": \"/home/runner/_work/gdc-nas/gdc-nas/sdk/gooddata-api-client/gooddata_api_client/model\", \"output_mode\": \"content\"}", "truncated": false}]}