Merge branch 'release' of https://github.com/appsmithorg/appsmith into release
This commit is contained in:
commit
bc40d337f5
|
|
@ -13,6 +13,7 @@ import {
|
|||
getAllUsers,
|
||||
getCurrentOrg,
|
||||
} from "selectors/organizationSelectors";
|
||||
import Spinner from "components/editorComponents/Spinner";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import { InviteUsersToOrgFormValues, inviteUsersToOrg } from "./helpers";
|
||||
import { INVITE_USERS_TO_ORG_FORM } from "constants/forms";
|
||||
|
|
@ -110,6 +111,12 @@ const StyledButton = styled(Button)`
|
|||
}
|
||||
`;
|
||||
|
||||
const Loading = styled(Spinner)`
|
||||
padding-top: 10px;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const validateFormValues = (values: { users: string; role: string }) => {
|
||||
if (values.users && values.users.length > 0) {
|
||||
const _users = values.users.split(",").filter(Boolean);
|
||||
|
|
@ -158,6 +165,7 @@ const OrgInviteUsersForm = (props: any) => {
|
|||
fetchCurrentOrg,
|
||||
currentOrg,
|
||||
isApplicationInvite,
|
||||
isLoading,
|
||||
} = props;
|
||||
|
||||
const currentPath = useLocation().pathname;
|
||||
|
|
@ -237,16 +245,20 @@ const OrgInviteUsersForm = (props: any) => {
|
|||
type="submit"
|
||||
/>
|
||||
</StyledInviteFieldGroup>
|
||||
<UserList style={{ justifyContent: "space-between" }}>
|
||||
{allUsers.map((user: { username: string; roleName: string }) => {
|
||||
return (
|
||||
<div className="user" key={user.username}>
|
||||
<div>{user.username}</div>
|
||||
<div>{user.roleName}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</UserList>
|
||||
{isLoading ? (
|
||||
<Loading size={30} />
|
||||
) : (
|
||||
<UserList style={{ justifyContent: "space-between" }}>
|
||||
{allUsers.map((user: { username: string; roleName: string }) => {
|
||||
return (
|
||||
<div className="user" key={user.username}>
|
||||
<div>{user.username}</div>
|
||||
<div>{user.roleName}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</UserList>
|
||||
)}
|
||||
{!pathRegex.test(currentPath) && canManage && (
|
||||
<Button
|
||||
className="manageUsers"
|
||||
|
|
@ -269,6 +281,7 @@ export default connect(
|
|||
roles: getRolesForField(state),
|
||||
allUsers: getAllUsers(state),
|
||||
currentOrg: getCurrentOrg(state),
|
||||
isLoading: state.ui.orgs.loadingStates.isFetchAllUsers,
|
||||
};
|
||||
},
|
||||
(dispatch: any) => ({
|
||||
|
|
|
|||
|
|
@ -84,4 +84,10 @@ public class PageController extends BaseController<PageService, Page, String> {
|
|||
return service.delete(id)
|
||||
.map(deletedResource -> new ResponseDTO<>(HttpStatus.OK.value(), deletedResource, null));
|
||||
}
|
||||
|
||||
@PostMapping("/clone/{pageId}")
|
||||
public Mono<ResponseDTO<Page>> clonePage(@PathVariable String pageId) {
|
||||
return applicationPageService.clonePage(pageId)
|
||||
.map(page -> new ResponseDTO<>(HttpStatus.CREATED.value(), page, null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,4 +23,6 @@ public interface ApplicationPageService {
|
|||
Mono<Application> cloneApplication(Application application);
|
||||
|
||||
Mono<Application> deleteApplication(String id);
|
||||
|
||||
Mono<Page> clonePage(String pageId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,19 +5,23 @@ import com.appsmith.server.acl.AclPermission;
|
|||
import com.appsmith.server.acl.PolicyGenerator;
|
||||
import com.appsmith.server.constants.AnalyticsEvents;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Action;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.ApplicationPage;
|
||||
import com.appsmith.server.domains.Layout;
|
||||
import com.appsmith.server.domains.Organization;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.dtos.ApplicationPagesDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.repositories.ApplicationRepository;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -26,6 +30,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.server.acl.AclPermission.MANAGE_ACTIONS;
|
||||
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
|
||||
import static com.appsmith.server.acl.AclPermission.MANAGE_PAGES;
|
||||
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
|
||||
|
|
@ -40,26 +45,32 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
|
|||
private final PageService pageService;
|
||||
private final SessionUserService sessionUserService;
|
||||
private final OrganizationService organizationService;
|
||||
private final LayoutActionService layoutActionService;
|
||||
|
||||
private final AnalyticsService analyticsService;
|
||||
private final PolicyGenerator policyGenerator;
|
||||
|
||||
private final ApplicationRepository applicationRepository;
|
||||
private final ActionService actionService;
|
||||
|
||||
public ApplicationPageServiceImpl(ApplicationService applicationService,
|
||||
PageService pageService,
|
||||
SessionUserService sessionUserService,
|
||||
OrganizationService organizationService,
|
||||
LayoutActionService layoutActionService,
|
||||
AnalyticsService analyticsService,
|
||||
PolicyGenerator policyGenerator,
|
||||
ApplicationRepository applicationRepository) {
|
||||
ApplicationRepository applicationRepository,
|
||||
ActionService actionService) {
|
||||
this.applicationService = applicationService;
|
||||
this.pageService = pageService;
|
||||
this.sessionUserService = sessionUserService;
|
||||
this.organizationService = organizationService;
|
||||
this.layoutActionService = layoutActionService;
|
||||
this.analyticsService = analyticsService;
|
||||
this.policyGenerator = policyGenerator;
|
||||
this.applicationRepository = applicationRepository;
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
public Mono<Page> createPage(Page page) {
|
||||
|
|
@ -324,4 +335,85 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
|
|||
.flatMap(deletedObj -> analyticsService.sendEvent(AnalyticsEvents.DELETE + "_" + deletedObj.getClass().getSimpleName().toUpperCase(), (Application) deletedObj));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Page> clonePage(String pageId) {
|
||||
|
||||
// Find the source page and then prune the page layout fields to only contain the required fields that should be
|
||||
// copied.
|
||||
Mono<Page> sourcePageMono = pageService.findById(pageId, MANAGE_PAGES)
|
||||
.flatMap(page -> Flux.fromIterable(page.getLayouts())
|
||||
.map(layout -> layout.getDsl())
|
||||
.map(dsl -> {
|
||||
Layout newLayout = new Layout();
|
||||
String id = new ObjectId().toString();
|
||||
newLayout.setId(id);
|
||||
newLayout.setDsl(dsl);
|
||||
return newLayout;
|
||||
})
|
||||
.collectList()
|
||||
.map(layouts -> {
|
||||
page.setLayouts(layouts);
|
||||
return page;
|
||||
}));
|
||||
|
||||
Flux<Action> sourceActionFlux = actionService.findByPageId(pageId, MANAGE_ACTIONS);
|
||||
|
||||
return sourcePageMono
|
||||
.flatMap(page -> {
|
||||
Mono<ApplicationPagesDTO> pageNamesMono = pageService
|
||||
.findNamesByApplicationId(page.getApplicationId());
|
||||
return pageNamesMono
|
||||
// Set a unique name for the cloned page and then create the page.
|
||||
.flatMap(pageNames -> {
|
||||
Set<String> names = pageNames.getPages()
|
||||
.stream()
|
||||
.map(pageNameIdDTO -> pageNameIdDTO.getName()).collect(Collectors.toSet());
|
||||
|
||||
String newPageName = page.getName() + " Copy";
|
||||
int i = 0;
|
||||
String name = newPageName;
|
||||
while(names.contains(name)) {
|
||||
i++;
|
||||
name = newPageName + i;
|
||||
}
|
||||
newPageName = name;
|
||||
// Now we have a unique name. Proceed with creating the copy of the page
|
||||
page.setId(null);
|
||||
page.setName(newPageName);
|
||||
return pageService.createDefault(page);
|
||||
});
|
||||
})
|
||||
.flatMap(page -> {
|
||||
String newPageId = page.getId();
|
||||
return sourceActionFlux
|
||||
.flatMap(action -> {
|
||||
action.setId(null);
|
||||
action.setPageId(newPageId);
|
||||
return actionService.create(action);
|
||||
})
|
||||
.collectList()
|
||||
.thenReturn(page);
|
||||
})
|
||||
// Calculate the onload actions for this page now that the page and actions have been created
|
||||
.flatMap(savedPage -> {
|
||||
List<Layout> layouts = savedPage.getLayouts();
|
||||
|
||||
return Flux.fromIterable(layouts)
|
||||
.flatMap(layout -> layoutActionService.updateLayout(savedPage.getId(), layout.getId(), layout))
|
||||
.collectList()
|
||||
.thenReturn(savedPage);
|
||||
})
|
||||
.flatMap(page -> {
|
||||
Mono<Application> applicationMono = applicationService.findById(page.getApplicationId(), MANAGE_APPLICATIONS);
|
||||
return applicationMono
|
||||
.flatMap(application -> {
|
||||
ApplicationPage applicationPage = new ApplicationPage();
|
||||
applicationPage.setId(page.getId());
|
||||
application.getPages().add(applicationPage);
|
||||
return applicationService.save(application)
|
||||
.thenReturn(page);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ public class LayoutActionServiceImpl implements LayoutActionService {
|
|||
private final ActionService actionService;
|
||||
private final PageService pageService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ApplicationPageService applicationPageService;
|
||||
private final AnalyticsService analyticsService;
|
||||
/*
|
||||
* This pattern finds all the String which have been extracted from the mustache dynamic bindings.
|
||||
|
|
@ -67,12 +66,10 @@ public class LayoutActionServiceImpl implements LayoutActionService {
|
|||
public LayoutActionServiceImpl(ActionService actionService,
|
||||
PageService pageService,
|
||||
ObjectMapper objectMapper,
|
||||
ApplicationPageService applicationPageService,
|
||||
AnalyticsService analyticsService) {
|
||||
this.actionService = actionService;
|
||||
this.pageService = pageService;
|
||||
this.objectMapper = objectMapper;
|
||||
this.applicationPageService = applicationPageService;
|
||||
this.analyticsService = analyticsService;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.appsmith.server.services;
|
||||
|
||||
import com.appsmith.external.models.Policy;
|
||||
import com.appsmith.server.configurations.WithMockAppsmithUser;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.Page;
|
||||
|
|
@ -17,7 +16,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
|
@ -174,6 +172,44 @@ public class PageServiceTest {
|
|||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void clonePage() throws ParseException {
|
||||
Policy managePagePolicy = Policy.builder().permission(MANAGE_PAGES.getValue())
|
||||
.users(Set.of("api_user"))
|
||||
.build();
|
||||
Policy readPagePolicy = Policy.builder().permission(READ_PAGES.getValue())
|
||||
.users(Set.of("api_user"))
|
||||
.build();
|
||||
|
||||
Page testPage = new Page();
|
||||
testPage.setName("PageServiceTest CloneTest Source");
|
||||
setupTestApplication();
|
||||
testPage.setApplicationId(application.getId());
|
||||
|
||||
Mono<Page> pageMono = applicationPageService.createPage(testPage)
|
||||
.flatMap(page -> applicationPageService.clonePage(page.getId()));
|
||||
|
||||
Object parsedJson = new JSONParser(JSONParser.MODE_PERMISSIVE).parse(FieldName.DEFAULT_PAGE_LAYOUT);
|
||||
StepVerifier
|
||||
.create(pageMono)
|
||||
.assertNext(page -> {
|
||||
assertThat(page).isNotNull();
|
||||
assertThat(page.getId()).isNotNull();
|
||||
assertThat("PageServiceTest CloneTest Source Copy".equals(page.getName()));
|
||||
|
||||
assertThat(page.getPolicies()).isNotEmpty();
|
||||
assertThat(page.getPolicies()).containsOnly(managePagePolicy, readPagePolicy);
|
||||
|
||||
assertThat(page.getLayouts()).isNotEmpty();
|
||||
assertThat(page.getLayouts().get(0).getDsl()).isEqualTo(parsedJson);
|
||||
assertThat(page.getLayouts().get(0).getWidgetNames()).isNotEmpty();
|
||||
assertThat(page.getLayouts().get(0).getPublishedDsl()).isNullOrEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void purgeAllPages() {
|
||||
pageService.deleteAll();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user