Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
allyoucanmap committed Aug 27, 2024
1 parent e69bc1b commit 6fbe38e
Show file tree
Hide file tree
Showing 24 changed files with 1,325 additions and 86 deletions.
6 changes: 5 additions & 1 deletion geonode_mapstore_client/client/js/api/geonode/v2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export const getResources = ({
sort,
f,
customFilters = [],
config,
...params
}) => {
const _params = {
Expand All @@ -146,6 +147,7 @@ export const getResources = ({
};
return axios.get(parseDevHostname(endpoints[RESOURCES]), {
params: _params,
config,
...paramsSerializer()
})
.then(({ data }) => {
Expand Down Expand Up @@ -336,7 +338,9 @@ export const getDatasetByPk = (pk) => {
},
...paramsSerializer()
})
.then(({ data }) => data.dataset);
.then(({ data }) => {
return data.dataset;
});
};

export const getDocumentByPk = (pk) => {
Expand Down
4 changes: 2 additions & 2 deletions geonode_mapstore_client/client/js/apps/gn-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ document.addEventListener('DOMContentLoaded', function() {
initialActions: [
updateGeoNodeSettings.bind(null, settings)
]
});
}, withExtensions(StandardApp));
}, withExtensions(StandardApp));
});
});
});
});
103 changes: 103 additions & 0 deletions geonode_mapstore_client/client/js/apps/gn-metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2022, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import { connect } from 'react-redux';
import main from '@mapstore/framework/components/app/main';
import MetadataRoute from '@js/routes/Metadata';
import MainLoader from '@js/components/MainLoader';
import Router, { withRoutes } from '@js/components/Router';
import security from '@mapstore/framework/reducers/security';
import {
getEndpoints,
getConfiguration,
getAccountInfo
} from '@js/api/geonode/v2';
import {
setupConfiguration,
initializeApp,
getPluginsConfiguration,
getPluginsConfigOverride
} from '@js/utils/AppUtils';
import pluginsDefinition, { storeEpicsNamesToExclude, cleanEpics } from '@js/plugins/index';
import gnsettings from '@js/reducers/gnsettings';
import { updateGeoNodeSettings } from '@js/actions/gnsettings';
import { METADATA_ROUTES, appRouteComponentTypes } from '@js/utils/AppRoutesUtils';

const requires = {};

initializeApp();

const DEFAULT_LOCALE = {};
const ConnectedRouter = connect((state) => ({
locale: state?.locale || DEFAULT_LOCALE
}))(Router);

const viewer = {
[appRouteComponentTypes.METADATA]: MetadataRoute
};

const routes = METADATA_ROUTES.map(({ component, ...config }) => ({ ...config, component: viewer[component] }));

document.addEventListener('DOMContentLoaded', function() {
getEndpoints().then(() => {
Promise.all([
getConfiguration(),
getAccountInfo()
])
.then(([localConfig, user]) => {

setupConfiguration({ localConfig, user })
.then(({
securityState,
pluginsConfigKey,
geoNodeConfiguration,
configEpics,
onStoreInit,
settings
}) => {

const appEpics = cleanEpics({
...configEpics
});

storeEpicsNamesToExclude(appEpics);

main({
appComponent: withRoutes(routes)(ConnectedRouter),
pluginsConfig: getPluginsConfigOverride(getPluginsConfiguration(localConfig.plugins, pluginsConfigKey)),
targetId: 'ms-container',
loaderComponent: MainLoader,
pluginsDef: {
plugins: {
...pluginsDefinition.plugins
},
requires: {
...requires,
...pluginsDefinition.requires
}
},
initialState: {
defaultState: {
...securityState
}
},
themeCfg: null,
appReducers: {
security,
gnsettings
},
appEpics,
onStoreInit,
geoNodeConfiguration,
initialActions: [
updateGeoNodeSettings.bind(null, settings)
]
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ import moment from 'moment';

import Button from '@js/components/Button';
import Tabs from '@js/components/Tabs';
import DetailsAttributeTable from '@js/components/DetailsPanel/DetailsAttributeTable';
import DetailsLinkedResources from '@js/components/DetailsPanel/DetailsLinkedResources';
import Message from '@mapstore/framework/components/I18N/Message';
import DetailsLocations from '@js/components/DetailsPanel/DetailsLocations';
import DetailsAssets from '@js/components/DetailsPanel/DetailsAssets';

const replaceTemplateString = (properties, str) => {
return Object.keys(properties).reduce((updatedStr, key) => {
Expand Down Expand Up @@ -143,12 +139,8 @@ function DetailsInfoFields({ fields, formatHref }) {
</div>);
}

const tabTypes = {
'attribute-table': DetailsAttributeTable,
'linked-resources': DetailsLinkedResources,
'locations': DetailsLocations,
'tab': DetailsInfoFields,
'assets': DetailsAssets
const defaultTabTypes = {
'tab': DetailsInfoFields
};

const parseTabItems = (items) => {
Expand All @@ -160,17 +152,22 @@ const isDefaultTabType = (type) => type === 'tab';

function DetailsInfo({
tabs = [],
tabTypes: tabTypesProp,
...props
}) {
const tabTypes = {
...defaultTabTypes,
...tabTypesProp
};
const filteredTabs = tabs
.filter((tab) => !tab?.disableIf)
.filter((tab) => !tab?.disableIf && tabTypes[tab?.type])
.map((tab) =>
({
...tab,
items: isDefaultTabType(tab.type) ? parseTabItems(tab?.items) : tab?.items,
Component: tabTypes[tab.type] || tabTypes.tab
}))
.filter(tab => !isEmpty(tab?.items));
.filter(tab => tab.editable ? true : !isEmpty(tab?.items));
const [selectedTabId, onSelect] = useState(filteredTabs?.[0]?.id);
return (
<Tabs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,49 @@ import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';

import FaIcon from '@js/components/FaIcon';
import Button from '@js/components/Button';
import Message from '@mapstore/framework/components/I18N/Message';
import { getResources } from '@js/api/geonode/v2';
import SelectInfiniteScroll from '@js/components/SelectInfiniteScroll';
import { ProcessTypes } from '@js/utils/ResourceServiceUtils';

const DetailLinkedResource = ({resources, type}) => {
const DetailLinkedResource = ({resources, type, onRemove}) => {
return !isEmpty(resources) && (
<>
<Message msgId={`gnviewer.linkedResources.${type}`} />
{resources.map((field, key) => {
return (<div key={key} className="gn-details-info-fields">
<div className="gn-details-info-row linked-resources">
{field.icon && <FaIcon name={field.icon} />}
<a key={field.pk} href={field.detail_url}>
<a key={field.pk} href={field.detail_url} style={{ flex: 1 }}>
{field.title}
</a>
{onRemove && <Button onClick={() => onRemove(field)}>
<FaIcon name="trash" />
</Button>}
</div>
</div>);
})}
</>
);
};

const DetailsLinkedResources = ({ fields, resourceTypesInfo }) => {
const linkedToFields = fields?.linkedTo?.map(resource=> ({...resource, icon: resourceTypesInfo[resource.resource_type]?.icon}));
const linkedByFields = fields?.linkedBy?.map(resource=> ({...resource, icon: resourceTypesInfo[resource.resource_type]?.icon}));
const DetailsLinkedResources = ({ fields, resource: resourceProp, resourceTypesInfo, onLinkResource, loading, canEdit }) => {
const linkedToFields = fields?.linkedTo?.map(resource=> ({...resource, icon: resourceTypesInfo[resource.resource_type]?.icon})) || [];
const linkedByFields = fields?.linkedBy?.map(resource=> ({...resource, icon: resourceTypesInfo[resource.resource_type]?.icon})) || [];
const source = resourceProp?.pk;

const linkedResources = [
{
resources: linkedToFields?.filter(resource => !resource.internal) ?? [],
type: 'linkedTo'
type: 'linkedTo',
onRemove: canEdit && onLinkResource ? (target) => {
onLinkResource({
source,
target,
processType: ProcessTypes.REMOVE_LINKED_RESOURCE
});
} : undefined
},
{
resources: linkedByFields?.filter(resource => !resource.internal) ?? [],
Expand All @@ -55,8 +70,43 @@ const DetailsLinkedResources = ({ fields, resourceTypesInfo }) => {

return (
<div className="linked-resources">
{canEdit && onLinkResource && <SelectInfiniteScroll
disabled={!!loading}
placeholder="Select related resource..."
onChange={(selected) => {
const target = selected?.target;
onLinkResource({
source,
target,
processType: ProcessTypes.LINK_RESOURCE
});
}}
loadOptions={({ ...params }) => getResources(params)
.then((response) => {
return {
...response,
results: response.resources.map((resource) => {
return {
...resource,
selectOption: {
target: {
internal: false,
pk: resource.pk,
title: resource.title,
resource_type: resource.resource_type,
detail_url: resource.detail_url,
thumbnail_url: resource.thumbnail_url
},
value: resource.pk,
label: <><FaIcon name={resourceTypesInfo[resource.resource_type]?.icon}/>{' '}{resource.title}</>
}
};
})
};
})}
/>}
{
linkedResources.map(({resources, type})=> <DetailLinkedResource resources={resources} type={type}/>)
linkedResources.map(({resources, type, onRemove })=> <DetailLinkedResource resources={resources} type={type} onRemove={onRemove}/>)
}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ function DetailsPanel({
enableMapViewer,
onClose,
tabs,
tabTypes,
pathname,
toolbarItems,
onSetExtent
Expand Down Expand Up @@ -292,7 +293,7 @@ function DetailsPanel({
: null}
</div>
</div>
<DetailsInfo tabs={tabs} formatHref={formatHref} allowEdit={activeEditMode} resourceTypesInfo={types} resource={resource} onSetExtent={onSetExtent}/>
<DetailsInfo tabs={tabs} tabTypes={tabTypes} formatHref={formatHref} allowEdit={activeEditMode} resourceTypesInfo={types} resource={resource} onSetExtent={onSetExtent}/>
</section>
</div>
);
Expand Down
37 changes: 34 additions & 3 deletions geonode_mapstore_client/client/js/epics/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,25 @@ export const closeDatasetCatalogPanel = (action$, store) => action$.ofType(NEW_M
return Observable.of(setControlProperty('datasetsCatalog', 'enabled', false));
});

const updateLinkedResources = ({
linkedResources,
target,
linkKey = 'linkedTo',
processType
}) => {
if (!target?.pk) {
return null;
}
const currentLinkList = linkedResources[linkKey] || [];
return {
...linkedResources,
[linkKey]: processType === ProcessTypes.LINK_RESOURCE ? [
...currentLinkList,
target
] : currentLinkList.filter(link => link.pk !== target.pk)
};
};

export const gnManageLinkedResource = (action$, store) =>
action$.ofType(MANAGE_LINKED_RESOURCE)
.switchMap((action) => {
Expand All @@ -644,13 +663,23 @@ export const gnManageLinkedResource = (action$, store) =>
observable$ = resourceObservable?.removeLinkedResourceObservable;
linkedResourceFn = removeLinkedResourcesByPk;
}
const linkedResources = updateLinkedResources({
linkedResources: resource?.data?.linkedResources,
linkKey: source === resource?.data?.pk ? 'linkedTo' : 'linkedBy',
target,
processType
});
const targetPk = target?.pk || target;
return Observable.concat(
...(isLinkResource ? [Observable.of(setResourcePathParameters({ ...params, pk: target}))] : []),
Observable.defer(() => linkedResourceFn(source, target))
...(isLinkResource ? [Observable.of(setResourcePathParameters({ ...params, pk: targetPk }))] : []),
Observable.defer(() => linkedResourceFn(source, targetPk))
.switchMap((response) =>
Observable.concat(
observable$({response, source, resource}),
observable$ ? observable$({response, source, resource}) : Observable.empty(),
Observable.of(
...(linkedResources ? [updateResourceProperties({
linkedResources
})] : []),
successNotification({
title: "gnviewer.linkedResource.title",
message: `gnviewer.linkedResource.message.success.${processType}`}
Expand All @@ -659,10 +688,12 @@ export const gnManageLinkedResource = (action$, store) =>
title: "gnviewer.linkedResource.title",
message: `gnviewer.linkedResource.message.failure.${processType}`
})))
/*
.let(wrapStartStop(
setControlProperty(processType, 'loading', true),
setControlProperty(processType, 'loading', false)
))
*/
);
});

Expand Down
4 changes: 3 additions & 1 deletion geonode_mapstore_client/client/js/plugins/DetailViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { mapSelector } from '@mapstore/framework/selectors/map';
import { parsePluginConfigExpressions } from '@js/utils/MenuUtils';
import usePluginItems from '@js/hooks/usePluginItems';
import { getResourceTypesInfo } from '@js/utils/ResourceUtils';
import tabTypes from '@js/plugins/detailviewer/tabTypes';

const ConnectedDetailsPanel = connect(
createSelector([
Expand All @@ -71,7 +72,8 @@ const ConnectedDetailsPanel = connect(
initialBbox: mapData?.bbox,
enableMapViewer: showMapThumbnail,
downloading,
resourceId: resource.pk
resourceId: resource.pk,
tabTypes
})),
{
closePanel: setControlProperty.bind(null, 'rightOverlay', 'enabled', false),
Expand Down
Loading

0 comments on commit 6fbe38e

Please sign in to comment.