Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions public/reearth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ extensions:
field: data_source_type
type: string
value: cms_integration_api
- id: cms_project_id
title: CMS Project ID
type: string
availableIf:
field: data_source_type
type: string
value: cms_integration_api
- id: cms_model_id
title: CMS Model ID
type: string
Expand Down Expand Up @@ -94,14 +101,18 @@ extensions:
field: location_type
type: string
value: geojson_field
- id: infobox_fields
title: Infobox Fields (comma-separated)
type: string
ui: multiline
- id: marker_appearance
title: Marker Appearance
type: string
ui: multiline
- id: inspector
title: Inspector
fields:
- id: display_fields
title: Display Fields
description: "Specify the fields to display in the infobox, separated by commas. Left empty to show all fields."
type: string
ui: multiline
- id: inspector_block
type: infoboxBlock
name: CMS Data Inspector Block
3 changes: 2 additions & 1 deletion src/extensions/inspector_block/inspector_block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const sendProperties = () => {
reearth.ui.postMessage({
action: "getProperties",
payload:
reearth.layers.selectedFeature?.properties?.__original || undefined,
reearth.layers.selectedFeature?.properties?.__inspector_fields ||
undefined,
});
};

Expand Down
79 changes: 77 additions & 2 deletions src/extensions/visualizer/main/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type WidgetProperty = {
server_api_key?: string;
integration_api_base_url?: string;
integration_api_key?: string;
cms_project_id?: string;
cms_model_id?: string;
};
appearance: {
Expand All @@ -25,6 +26,12 @@ type Schema = {
type: string;
}[];

// Sub-collect Asset type
type Asset = {
id: string;
url: string;
};

type Item = {
id: string;
fields: Field[];
Expand Down Expand Up @@ -91,13 +98,67 @@ export default () => {
if (
!widgetProperty.api.integration_api_base_url ||
!widgetProperty.api.integration_api_key ||
!widgetProperty.api.cms_project_id ||
!widgetProperty.api.cms_model_id
) {
console.warn(
"Please set the Integration API Base URL, Integration API Key, and CMS Model ID in the widget properties."
"Please set the Integration API Base URL, Integration API Key, CMS Project ID, and CMS Model ID in the widget properties."
);
return;
}

// Fetch Assets with pagination
let assets: Asset[];
try {
const baseUrl = `${widgetProperty.api.integration_api_base_url}/projects/${widgetProperty.api.cms_project_id}/assets`;
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${widgetProperty.api.integration_api_key}`,
};
// First request to get total count
const firstResponse = await fetch(`${baseUrl}?perPage=100&page=1`, {
method: "GET",
headers,
});

if (!firstResponse.ok) {
throw new Error(`HTTP error! status: ${firstResponse.status}`);
}

const firstData = await firstResponse.json();
const totalCount = firstData.totalCount;
const perPage = 100;
const totalPages = Math.ceil(totalCount / perPage);

assets = firstData.items || [];

// Fetch remaining pages if there are more
if (totalPages > 1) {
const pagePromises = [];
for (let page = 2; page <= totalPages; page++) {
pagePromises.push(
fetch(`${baseUrl}?perPage=${perPage}&page=${page}`, {
method: "GET",
headers,
})
);
}

const responses = await Promise.all(pagePromises);

for (const response of responses) {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
assets = assets.concat(data.items || []);
}
}
postMsg("setAssets", assets);
} catch (error) {
console.error("Error fetching assets:", error);
}

// Fetch Schema
let schema: Schema;
try {
Expand Down Expand Up @@ -169,17 +230,31 @@ export default () => {
}

// append schema's name to each item
// replace asset id with asset url in each item
allItems = allItems.map((item: Item) => ({
...item,
fields: [
...item.fields.map((field: Field) => ({
...field,
name: schema.find((s) => s.key === field.key)?.name,
value:
field.type === "asset" && typeof field.value === "string"
? assets.find((a) => a.id === field.value)?.url ||
field.value
: field.type === "asset" && Array.isArray(field.value)
? (field.value as string[])
.map(
(assetId) =>
assets.find((a) => a.id === assetId)?.url ||
assetId
)
.reverse()
: field.value,
})),
],
}));

console.log("items", allItems);
console.log("Debug: items", allItems);
postMsg("addLayer", allItems);
} catch (error) {
console.error("Error fetching data:", error);
Expand Down
66 changes: 42 additions & 24 deletions src/extensions/visualizer/visualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,27 @@ type VisualizationConfig = {
marker_appearance?: string;
};

type InspectorConfig = {
display_fields?: string;
};

type WidgetProperty = {
// ignore tha api group
visualization: VisualizationConfig;
inspector: InspectorConfig;
};

type ItemField = {
id: string;
key: string;
type: string;
value: unknown;
name?: string;
};

type Item = {
id: string;
fields: {
id: string;
key: string;
type: string;
value: unknown;
}[];
fields: ItemField[];
};

type UIMessage =
Expand Down Expand Up @@ -119,31 +127,24 @@ const generateGeoJSON = (
}

// Convert items to GeoJSON features
const fields = config.infobox_fields
? config.infobox_fields.split(",").map((f) => f.trim())
const inspectorConfig =
(reearth.extension?.widget?.property as WidgetProperty)?.inspector || {};
const displayFields = inspectorConfig.display_fields
? inspectorConfig.display_fields.split(",").map((f) => f.trim())
: [];

const features = items
.map((item) => {
// Prepare properties
const properties: Record<string, any> = {};

if (fields.length === 0) {
// If no infobox fields specified, include all fields
item.fields.forEach((field) => {
properties[field.key] = field.value;
});
properties.__original = item.fields;
} else {
properties.__original = [];
fields.forEach((field) => {
const fieldObj = item.fields.find((f) => f.key === field);
if (fieldObj) {
properties[field] = fieldObj.value;
properties.__original.push(fieldObj);
}
});
}
// Add all fields as properties
item.fields.forEach((field) => {
properties[field.key] = field.value;
});

// Add filtered fields for inspector
properties.__inspector_fields = filterFields(item.fields, displayFields);

// Get location
const coordinates = [];
Expand Down Expand Up @@ -245,3 +246,20 @@ const generateGeoJSON = (

return geoJSON;
};

const filterFields = (
originalFields: ItemField[],
displayFieldKeys: string[]
) => {
if (displayFieldKeys.length === 0) {
return originalFields;
}
const filteredFields = [];
for (const key of displayFieldKeys) {
const field = originalFields.find((f) => f.key === key);
if (field) {
filteredFields.push(field);
}
}
return filteredFields;
};