Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduces async processes for cards actions (delete) #412

Merged
merged 1 commit into from
Aug 11, 2021
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
10 changes: 10 additions & 0 deletions geonode_mapstore_client/client/js/actions/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const RESOURCE_CONFIG_ERROR = 'GEONODE:RESOURCE_CONFIG_ERROR';
export const SET_RESOURCE_COMPACT_PERMISSIONS = 'GEONODE:SET_RESOURCE_COMPACT_PERMISSIONS';
export const UPDATE_RESOURCE_COMPACT_PERMISSIONS = 'GEONODE:UPDATE_RESOURCE_COMPACT_PERMISSIONS';
export const RESET_GEO_LIMITS = 'GEONODE:RESET_GEO_LIMITS';
export const PROCESS_RESOURCES = 'GEONODE:PROCESS_RESOURCES';

/**
* Actions for GeoNode resource
Expand Down Expand Up @@ -250,3 +251,12 @@ export function resetGeoLimits() {
type: RESET_GEO_LIMITS
};
}

export function processResources(processType, resources, redirectTo) {
return {
type: PROCESS_RESOURCES,
processType,
resources,
redirectTo
};
}
32 changes: 32 additions & 0 deletions geonode_mapstore_client/client/js/actions/resourceservice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2021, 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.
*/

export const START_ASYNC_PROCESS = 'GEONODE:START_ASYNC_PROCESS';
export const STOP_ASYNC_PROCESS = 'GEONODE:STOP_ASYNC_PROCESS';
export const UPDATE_ASYNC_PROCESS = 'GEONODE:UPDATE_ASYNC_PROCESS';

export function startAsyncProcess(payload) {
return {
type: START_ASYNC_PROCESS,
payload
};
}

export function updateAsyncProcess(payload) {
return {
type: UPDATE_ASYNC_PROCESS,
payload
};
}

export function stopAsyncProcess(payload) {
return {
type: STOP_ASYNC_PROCESS,
payload
};
}
14 changes: 13 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 @@ -677,6 +677,16 @@ export const updateCompactPermissionsByPk = (pk, body) => {
.then(({ data }) => data);
};

export const deleteResource = (resource) => {
return axios.delete(parseDevHostname(`${endpoints[RESOURCES]}/${resource.pk}/delete`))
.then(({ data }) => data);
};

export const copyResource = (resource) => {
return axios.put(parseDevHostname(`${endpoints[RESOURCES]}/${resource.pk}/copy`))
.then(({ data }) => data);
};

export default {
getEndpoints,
getResources,
Expand All @@ -703,5 +713,7 @@ export default {
getOwners,
getKeywords,
getCompactPermissionsByPk,
updateCompactPermissionsByPk
updateCompactPermissionsByPk,
deleteResource,
copyResource
};
4 changes: 4 additions & 0 deletions geonode_mapstore_client/client/js/apps/gn-catalogue.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import ViewerRoute from '@js/routes/Viewer';

import gnsearch from '@js/reducers/gnsearch';
import gnresource from '@js/reducers/gnresource';
import resourceservice from '@js/reducers/resourceservice';
import gnsettings from '@js/reducers/gnsettings';

import {
Expand All @@ -67,6 +68,7 @@ import {
} from '@js/epics';

import gnresourceEpics from '@js/epics/gnresource';
import resourceServiceEpics from '@js/epics/resourceservice';
import gnsearchEpics from '@js/epics/gnsearch';
import favoriteEpics from '@js/epics/favorite';
import maplayout from '@mapstore/framework/reducers/maplayout';
Expand Down Expand Up @@ -251,6 +253,7 @@ Promise.all([
appReducers: {
...standardReducers,
gnresource,
resourceservice,
gnsettings,
security,
maptype,
Expand All @@ -276,6 +279,7 @@ Promise.all([
gnSetDatasetsPermissions,
...pluginsDefinition.epics,
...gnresourceEpics,
...resourceServiceEpics,
...gnsearchEpics,
...favoriteEpics,
updateMapLayoutEpic
Expand Down
7 changes: 5 additions & 2 deletions geonode_mapstore_client/client/js/apps/gn-home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { connect } from 'react-redux';

import security from '@mapstore/framework/reducers/security';
import controls from '@mapstore/framework/reducers/controls';

import Home from '@js/routes/Home';

import gnsearch from '@js/reducers/gnsearch';
import gnresource from '@js/reducers/gnresource';
import resourceservice from '@js/reducers/resourceservice';
import gnsearchEpics from '@js/epics/gnsearch';
import gnsaveEpics from '@js/epics/gnsave';
import resourceServiceEpics from '@js/epics/resourceservice';

import {
getConfiguration,
Expand Down Expand Up @@ -78,12 +79,14 @@ Promise.all([
appReducers: {
gnsearch,
gnresource,
resourceservice,
security,
controls
},
appEpics: {
...gnsearchEpics,
...gnsaveEpics
...gnsaveEpics,
...resourceServiceEpics
},
geoNodeConfiguration
});
Expand Down
38 changes: 34 additions & 4 deletions geonode_mapstore_client/client/js/components/CardGrid/CardGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { withResizeDetector } from 'react-resize-detector';
import useLocalStorage from '@js/hooks/useLocalStorage';
import { hasPermissionsTo } from '@js/utils/MenuUtils';
import useInfiniteScroll from '@js/hooks/useInfiniteScroll';
import {
ProcessTypes,
ProcessStatus
} from '@js/utils/ResourceServiceUtils';

const Cards = withResizeDetector(({
resources,
Expand All @@ -23,7 +27,9 @@ const Cards = withResizeDetector(({
containerWidth,
width: detectedWidth,
buildHrefByTemplate,
options
options,
actions,
onAction
}) => {

const width = containerWidth || detectedWidth;
Expand Down Expand Up @@ -86,7 +92,15 @@ const Cards = withResizeDetector(({
>
{resources.map((resource, idx) => {
// enable allowedOptions (menu cards) only for list layout
const allowedOptions = (cardLayoutStyle === 'list') ? options
const { processes, ...data } = resource;
const isProcessing = processes
? !!processes.find(({ completed }) => !completed)
: false;
const deleteProcess = processes && processes.find(({ processType }) => processType === ProcessTypes.DELETE_RESOURCE);
const isDeleting = !!deleteProcess?.output?.status;
const isDeleted = deleteProcess?.output?.status === ProcessStatus.FINISHED;

const allowedOptions = (cardLayoutStyle === 'list' && !isProcessing) ? options
.filter((opt) => hasPermissionsTo(resource?.perms, opt?.perms, 'resource')) : [];

return (
Expand All @@ -95,12 +109,17 @@ const Cards = withResizeDetector(({
style={(layoutSpace(idx))}
>
<ResourceCard
className={`${isDeleted ? 'deleted' : ''}`}
active={isCardActive(resource)}
data={resource}
data={data}
formatHref={formatHref}
options={allowedOptions}
buildHrefByTemplate={buildHrefByTemplate}
layoutCardsStyle={cardLayoutStyle}
actions={actions}
onAction={onAction}
loading={isProcessing}
readOnly={isDeleted || isDeleting}
/>
</li>
);
Expand All @@ -123,7 +142,10 @@ const CardGrid = ({
messageId,
children,
buildHrefByTemplate,
scrollContainer
scrollContainer,
actions,
onAction,
onControl
}) => {

useInfiniteScroll({
Expand Down Expand Up @@ -157,6 +179,14 @@ const CardGrid = ({
isCardActive={isCardActive}
options={cardOptions}
buildHrefByTemplate={buildHrefByTemplate}
actions={actions}
onAction={(action, payload) => {
if (action.isControlled) {
onControl(action.processType, 'value', payload);
} else {
onAction(action.processType, payload, action.redirectTo);
}
}}
/>
<div className="gn-card-grid-pagination">
{loading && <Spinner animation="border" role="status">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '@js/utils/ResourceUtils';
import localizedProps from '@mapstore/framework/components/misc/enhancers/localizedProps';
import { getGeoLimits } from '@js/api/geonode/security';
import Spinner from '@js/components/Spinner';

const FormControl = localizedProps('placeholder')(FormControlRB);

Expand All @@ -34,7 +35,8 @@ function Permissions({
defaultGroupOptions,
enableGeoLimits,
requestGeoLimits = getGeoLimits,
resourceId
resourceId,
loading
}) {

const { entries = [], groups = [] } = permissionsCompactToLists(compactPermissions);
Expand Down Expand Up @@ -301,6 +303,11 @@ function Permissions({
<Message msgId="gnviewer.permissionsEntriesNoResults" />
</div>
}
{loading && (
<div className="gn-spinner-container">
<Spinner />
</div>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,27 @@ import React, { forwardRef } from 'react';
import Message from '@mapstore/framework/components/I18N/Message';
import FaIcon from '@js/components/FaIcon';
import Dropdown from '@js/components/Dropdown';
import Spinner from '@js/components/Spinner';
import { getUserName } from '@js/utils/SearchUtils';
import { getResourceTypesInfo } from '@js/utils/ResourceUtils';

function ALink({ href, readOnly, children }) {
return readOnly ? children : <a href={href}>{children}</a>;
}

const ResourceCard = forwardRef(({
data,
active,
options,
formatHref,
getTypesInfo,
layoutCardsStyle,
buildHrefByTemplate
buildHrefByTemplate,
readOnly,
actions,
onAction,
className,
loading
}, ref) => {

const res = data;
Expand All @@ -29,37 +40,39 @@ const ResourceCard = forwardRef(({
return (
<div
ref={ref}
className={`gn-resource-card${active ? ' active' : ''} gn-card-type-${layoutCardsStyle} ${layoutCardsStyle === 'list' ? 'rounded-0' : ''}`}
className={`gn-resource-card${active ? ' active' : ''}${readOnly ? ' read-only' : ''} gn-card-type-${layoutCardsStyle} ${layoutCardsStyle === 'list' ? 'rounded-0' : ''}${className ? ` ${className}` : ''}`}
>
<a
{!readOnly && <a
className="gn-resource-card-link"
href={formatHref({
pathname: `/detail/${res.resource_type}/${res.pk}`
})}
/>
/>}
<div className={`card-resource-${layoutCardsStyle}`}>
<img
className={`${(layoutCardsStyle === 'list') ? 'card-img-left' : 'card-img-top'}`}
src={res.thumbnail_url}
/>
<div className="card-body">
<div className="card-title">
{icon &&
{(icon && !loading) &&
<>
<a
<ALink
readOnly={readOnly}
href={formatHref({
query: {
'filter{resource_type.in}': res.resource_type
}
})}>
<FaIcon name={icon} />
</a>
</ALink>
</>}
<a href={formatHref({
{loading && <Spinner />}
<ALink readOnly={readOnly} href={formatHref({
pathname: `/detail/${res.resource_type}/${res.pk}`
})}>
{res.title}
</a>
</ALink>
</div>
<p
className="card-text gn-card-description"
Expand All @@ -69,15 +82,15 @@ const ResourceCard = forwardRef(({
<p
className="card-text gn-card-user"
>
<Message msgId="gnhome.author"/>: <a href={formatHref({
<Message msgId="gnhome.author"/>: <ALink readOnly={readOnly} href={formatHref({
query: {
'filter{owner.username.in}': res.owner.username
}
})}>{getUserName(res.owner)}</a>
})}>{getUserName(res.owner)}</ALink>
</p>

</div>
{options && options.length > 0 && <Dropdown
{(!readOnly && options && options.length > 0) && <Dropdown
className="gn-card-options"
pullRight
>
Expand All @@ -92,7 +105,16 @@ const ResourceCard = forwardRef(({
<Dropdown.Menu className={`gn-card-dropdown`} >
{options
.map((opt) => {

if (opt.type === 'button' && actions[opt.action]) {
return (
<Dropdown.Item
key={opt.action}
onClick={() => onAction(actions[opt.action], [res])}
>
<FaIcon name={opt.icon} /> <Message msgId={opt.labelId}/>
</Dropdown.Item>
);
}
const viewResourcebase = opt.perms.filter(obj => {
return obj.value === "view_resourcebase";
});
Expand All @@ -102,7 +124,7 @@ const ResourceCard = forwardRef(({
key={opt.href}
href={
(viewResourcebase.length > 0 ) ? formatHref({
pathname: `/detail/${res.resource_type}/${res.pk}`
pathname: `/${res.resource_type}/${res.pk}`
}) : buildHrefByTemplate(res, opt.href)
}
>
Expand All @@ -120,7 +142,8 @@ const ResourceCard = forwardRef(({
ResourceCard.defaultProps = {
links: [],
theme: 'light',
getTypesInfo: getResourceTypesInfo
getTypesInfo: getResourceTypesInfo,
formatHref: () => '#'
};

export default ResourceCard;
Loading