Skip to content

Commit

Permalink
Feat: Page Builder Import & Export Page (#1890)
Browse files Browse the repository at this point in the history
* feat(api-page-builder): wip export and import page API

* feat(app-page-builder): implement export and import page actions

* feat(api-file-manager): add tags and hideInFileManager in upload method args

* feat(apps/admin): add zipFileTypePlugin

* fix(app-page-builder): add accept prop in import page option

* chore(app/admin): add icon

* feat(app-page-builder): add import export icons

* fix(app-page-builder): add accept prop in import page option

* feat(api-page-builder): add pageExportTask

update page export and import mutation

* feat(api-page-builder): add export page workflow handler

* refactor(api-page-builder): move s3StreamHandler to exportPage

* feat(api): add exportPage lambda handler

* feat(api): add getPbExportPageTaskLambdaPolicy

remove todos

* feat(app-page-builder): add ExportPage button

* refactor(app-page-builder): remove import and export page button from page editor bar

* feat(app-page-builder): update import page workflow

* chore(api): add package.json for api-page-builder-page-export-task

* refactor(app-page-builder): move IMPORT_PAGE gql into pages.ts

* feat(app-page-builder): add page to PbPageDetailsPlugin type

* feat(app-page-builder): add ExportPageButton in PbPageDetailsPlugins

* refactor(api-page-builder): use uniqid to generate file key in export page task

* feat(ui): update DataList header cell span

* feat(app-admin): add onUploadCompletion prop to FileManagerView

* test(api-page-builder): add test for Page Export Task module

* chore(api): update api-page-builder-page-export-task dependencies

* chore: update yarn lock

* refactor(api-page-builder): remove archiveFormat option from ZipHandlerConfig

* fix(api-page-builder): add failed to PbPageExportTaskStatus

* feat(api-page-builder): update export page task status as failed in case of error

* refactor(api-page-builder): remove redundant code

* feat(app-admin): export hideDialog from useDialog hook

* feat(app-page-builder): handle cancel task

handle error in case of export page

* fix(app-page-builder): update copy export URL style

* fix(api-page-builder): handle inaccessible file in page export

* refactor(api-page-builder): skip updateFilesInPageData in case of no files

* refactor(api-page-builder): rename pageExportTask to exportPageTask

* refactor(api): rename api-page-builder-page-export-task to api-page-builder-export-page-task

* chore: update yarn lock

* refactor(app-page-builder): rename GET_EXPORT_PAGE_TASK GQL query

* refactor(api-page-builder): update exportPageTask test

* chore(api): add WEBINY_LOGS_FORWARD_URL in PageBuilder env

* fix(api-page-builder): update ExportPageTask type in page crud

* feat(api): add "api-page-builder-import-page" package

* feat(api): add resources for importPage function

* feat(api-page-builder): update export page handler

* feat(api): add importPages packages in pageBuilder

* feat(api-page-builder): add importPage handlers

* feat(api-page-builder): add importPages and exportPages mutations

* refactor(api-page-builder): remove openZipFile usage from create handler

* refactor(api-page-builder): update importPage implementation

* refactor(api): page builder handlers

* feat(api-page-builder): remove zip contents from storage after importing page

* feat(api): add "s3:ListBucket" action in getImportPageLambdaPolicy

* fix(api-page-builder): add stats and error logs in main task

* refactor(api-page-builder): use invokeHandlerClient

* refactor(api-page-builder): handle error in case of bad file

* feat(api-page-builder): handle zip file url as input

* refactor(api-page-builder): add payload type in invokeHandlerClient

* refactor(api-page-builder): update task stats

* refactor(api-page-builder): use payload type

* refactor(api-page-builder): add GSI

* feat(api-page-builder): add export pages combine and process handlers

* feat(api): add code for export pages combine and process handlers

* feat(api): update lambda policies

* feat(api): add resources for export pages handlers

* refactor(api-page-builder): rename extract to combine

* refactor(api-page-builder): revert self invoke condition

* feat(api-page-builder): update readExtractAndUploadZipFileContents helper

* refactor(api-page-builder): remove redundant code

* fix(api-page-builder): save export page url after completion

* fix(api-page-builder): add updateFilesInPageData helper

* refactor(api): remove redundant code

* refactor(api-page-builder): remove redundant code

* refactor(api-page-builder): rename importPages

* feat(api): add import export page handler name to graphql env

* feat(api-page-builder): implement exportPages and importPages mutation

* feat(api-page-builder): add pageImportExportTask

* refactor(app-page-builder): update import and export page gql

* refactor(api-page-builder): update pages.gql schema

* chore: update workspaces pacakges

* chore(api-page-builder): add unzipper as dependencies

* test(api-page-builder): remove redundant test code

* chore: update yarn lock file

* feat(app-page-builder): add assets

* feat(app-page-builder): implement Import Pages UI

* feat(app-page-builder): add className prop to Accordion component

* feat(app-admin): add style prop to Dialog

* feat(api-page-builder): save page data in subtask after completion

update page title after page creation

* feat(api-page-builder): add getPageImportExportSubTaskByStatus GQL query

* refactor(app-page-builder): remove redundant code

* feat(app-page-builder): close CategoriesDialog after select

* feat(api-page-builder): add revisionType to exportPages GQL

* feat(app-page-builder): implement export pages UI

* feat(app-page-builder): add useMultiSelect hook for pages

* feat(app-page-builder): add export page button in multiselect action

* refactor(app-page-builder): update PbExportPages GQL

* fix(api-page-builder): move error out of data in import pages

* feat(app-page-builder): add cancel icon

* feat(app-page-builder): update export pages UI

* feat(app-page-builder): add exportPageData to PageBuilderContext

* feat(app-page-builder): add getValue param to useMultiSelect

* feat(ui): add data to multiSelect props in DataList

* fix(app-page-builder): update page import export UI

* fix(api-page-builder): remove zip files after export

* refactor(api-page-builder): use s3Stream helpers

remove redundant code

* feat(api-page-builder-import-export): extract import export page logic into separate package

* refactor(api-page-builder): remove redundant code

* refactor(api): use api-page-builder-import-export package

* chore: update yarn lock

* fix(api-page-builder): modify context correctly

* fix(api): add pageBuilderImportExportPlugins

* feat(app-page-builder): add data-testid prop

* test: add addMatchImageSnapshotPlugin cypress command

* test: add import export pages workflow e2e test

* chore: add cypress-image-snapshot as dev dependency

* chore: add clipboard permission

* feat(api-page-builder-import-export-so-ddb): add ddb only storage operations package

* feat(api-page-builder-import-export): use storageOperations in pageImportExportTasks crud

* feat(api-page-builder-import-export): add params for crud plugins

* refactor(api-page-builder-import-export): update GQL schema

rename getPageImportExportSubTaskByStatus to listPageImportExportSubTask

* test(api-page-builder-import-export): add test for pageImportExportTask

* test(api-page-builder-import-export): add jest setup file

* feat(api-page-builder-import-export): update types with storageOperations

* chore(api-page-builder-import-export): update dependencies and ts configs

* feat(api): add pageBuilderDynamoDbElasticsearchPlugins and page task storageOperations

* chore: update yarn lock

* refactor(app-page-builder): update GQL schema

use listPageImportExportSubTask query

* feat(api-page-builder-import-export-so-ddb): add updateTaskStats method to storageOperations

* feat(api-page-builder-import-export): add updateStats to PageImportExportTaskStorageOperations

* refactor(api-page-builder-import-export): use updateStats from pageImportExportTask

remove updateMainTask helper

* test(api-page-builder-import-export): add test for updateStats

* chore: update yarn lock

* feat(api): add PageImportExport lambda resources for prod env

* feat(cwp-template-aws): add exportPages and importPages packages in api code

* feat(cwp-template-aws): add resources for page import export

* feat(cwp-template-aws): add pageBuilderImportExportPlugins to graphql lambda code

* fix(cwp-template-aws): update workspaces packages

* refactor(api-page-builder-import-export): update PageImportExportTaskStorageOperations type

* refactor(api-page-builder-import-export): use limit param to listTasks

* feat(cli): update upgrade command for 5.16.0

addNewFiles

* chore(cli): add fs-extra as dependency

* chore: update yarn lock

* chore: ran prettier

* refactor(cli): rename addNewFiles to copyFolders
  • Loading branch information
Ashu96 committed Oct 13, 2021
1 parent c212bb2 commit eb30332
Show file tree
Hide file tree
Showing 160 changed files with 9,825 additions and 161 deletions.
2 changes: 2 additions & 0 deletions api/code/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"@webiny/api-i18n-content": "^5.15.0",
"@webiny/api-i18n-ddb": "^5.15.0",
"@webiny/api-page-builder": "^5.15.0",
"@webiny/api-page-builder-import-export": "^5.15.0",
"@webiny/api-page-builder-import-export-so-ddb": "^5.15.0",
"@webiny/api-page-builder-so-ddb-es": "^5.15.0",
"@webiny/api-prerendering-service": "^5.15.0",
"@webiny/api-security": "^5.15.0",
Expand Down
5 changes: 5 additions & 0 deletions api/code/graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import securityAdminUsersDynamoDbStorageOperations from "@webiny/api-security-ad
import pageBuilderPlugins from "@webiny/api-page-builder/graphql";
import pageBuilderDynamoDbElasticsearchPlugins from "@webiny/api-page-builder-so-ddb-es";
import pageBuilderPrerenderingPlugins from "@webiny/api-page-builder/prerendering";
import pageBuilderImportExportPlugins from "@webiny/api-page-builder-import-export/graphql";
import { createStorageOperations } from "@webiny/api-page-builder-import-export-so-ddb";
import prerenderingServicePlugins from "@webiny/api-prerendering-service/client";
import dbPlugins from "@webiny/handler-db";
import { DynamoDbDriver } from "@webiny/db-dynamodb";
Expand Down Expand Up @@ -75,6 +77,9 @@ export const handler = createHandler({
pageBuilderPlugins(),
pageBuilderDynamoDbElasticsearchPlugins(),
pageBuilderPrerenderingPlugins(),
pageBuilderImportExportPlugins({
storageOperations: createStorageOperations({ documentClient })
}),
createFormBuilder({
storageOperations: createFormBuilderStorageOperations({
documentClient,
Expand Down
23 changes: 23 additions & 0 deletions api/code/graphql/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
{
"path": "../../../packages/api-page-builder-so-ddb-es"
},
{
"path": "../../../packages/api-page-builder-import-export"
},
{
"path": "../../../packages/api-page-builder-import-export-so-ddb"
},
{
"path": "../../../packages/api-tenancy"
},
Expand Down Expand Up @@ -117,12 +123,29 @@
"@webiny/handler-graphql": ["../../../packages/handler-graphql/src"],
"@webiny/api-page-builder/*": ["../../../packages/api-page-builder/src/*"],
"@webiny/api-page-builder": ["../../../packages/api-page-builder/src"],
"@webiny/api-page-builder-so-ddb-es/*": [
"../../../packages/api-page-builder-so-ddb-es/src/*"
],
"@webiny/api-page-builder-so-ddb-es": ["../../../packages/api-page-builder-so-ddb-es/src"],
"@webiny/api-page-builder-import-export/*": [
"../../../packages/api-page-builder-import-export/src/*"
],
"@webiny/api-page-builder-import-export": [
"../../../packages/api-page-builder-import-export/src"
],
"@webiny/api-page-builder-import-export-so-ddb/*": [
"../../../packages/api-page-builder-import-export-so-ddb/src/*"
],
"@webiny/api-page-builder-import-export-so-ddb": [
"../../../packages/api-page-builder-import-export-so-ddb/src/*"
],
"@webiny/api-form-builder/*": ["../../../packages/api-form-builder/src/*"],
"@webiny/api-form-builder": ["../../../packages/api-form-builder/src"],
"@webiny/api-form-builder-so-ddb-es/*": [
"../../../packages/api-form-builder-so-ddb-es/src/*"
],
"@webiny/api-form-builder-so-ddb-es": ["../../../packages/api-form-builder-so-ddb-es/src"],

"@webiny/api-security/*": ["../../../packages/api-security/src/*"],
"@webiny/api-security": ["../../../packages/api-security/src"],
"@webiny/api-tenancy/*": ["../../../packages/api-tenancy/src/*"],
Expand Down
33 changes: 33 additions & 0 deletions api/code/pageBuilder/exportPages/combine/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "api-page-builder-export-pages-combine",
"version": "0.1.0",
"scripts": {
"build": "yarn webiny run build",
"watch": "yarn webiny run watch"
},
"dependencies": {
"@webiny/api-elasticsearch": "^5.14.0",
"@webiny/api-file-manager": "^5.14.0",
"@webiny/api-file-manager-ddb-es": "^5.14.0",
"@webiny/api-file-manager-s3": "^5.14.0",
"@webiny/api-i18n": "^5.14.0",
"@webiny/api-i18n-content": "^5.14.0",
"@webiny/api-i18n-ddb": "^5.14.0",
"@webiny/api-page-builder": "^5.14.0",
"@webiny/api-page-builder-import-export": "^5.14.0",
"@webiny/api-page-builder-import-export-so-ddb": "^5.15.0",
"@webiny/api-page-builder-so-ddb-es": "^5.15.0",
"@webiny/api-security": "^5.14.0",
"@webiny/api-security-admin-users": "^5.14.0",
"@webiny/api-security-admin-users-cognito": "^5.14.0",
"@webiny/api-security-admin-users-so-ddb": "^5.14.0",
"@webiny/api-security-cognito-authentication": "^5.14.0",
"@webiny/api-tenancy": "^5.14.0",
"@webiny/cli": "^5.14.0",
"@webiny/db-dynamodb": "^5.14.0",
"@webiny/handler-aws": "^5.14.0",
"@webiny/handler-db": "^5.14.0",
"@webiny/handler-logs": "^5.14.0",
"@webiny/project-utils": "^5.14.0"
}
}
59 changes: 59 additions & 0 deletions api/code/pageBuilder/exportPages/combine/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { DocumentClient } from "aws-sdk/clients/dynamodb";
import { createHandler } from "@webiny/handler-aws";
import i18nPlugins from "@webiny/api-i18n/graphql";
import i18nDynamoDbStorageOperations from "@webiny/api-i18n-ddb";
import i18nContentPlugins from "@webiny/api-i18n-content/plugins";
import adminUsersPlugins from "@webiny/api-security-admin-users";
import securityAdminUsersDynamoDbStorageOperations from "@webiny/api-security-admin-users-so-ddb";
import pageBuilderPlugins from "@webiny/api-page-builder/graphql";
import pageBuilderDynamoDbElasticsearchPlugins from "@webiny/api-page-builder-so-ddb-es";
import pageBuilderImportExportPlugins from "@webiny/api-page-builder-import-export/graphql";
import { createStorageOperations } from "@webiny/api-page-builder-import-export-so-ddb";
import exportPagesCombinePlugins from "@webiny/api-page-builder-import-export/exportPages/combine";
import dbPlugins from "@webiny/handler-db";
import { DynamoDbDriver } from "@webiny/db-dynamodb";
import dynamoDbPlugins from "@webiny/db-dynamodb/plugins";
import elasticSearch from "@webiny/api-elasticsearch";
import fileManagerPlugins from "@webiny/api-file-manager/plugins";
import fileManagerDynamoDbElasticStorageOperation from "@webiny/api-file-manager-ddb-es";
import logsPlugins from "@webiny/handler-logs";
import fileManagerS3 from "@webiny/api-file-manager-s3";
import securityPlugins from "./security";

const documentClient = new DocumentClient({
convertEmptyValues: true,
region: process.env.AWS_REGION
});

const debug = process.env.DEBUG === "true";

export const handler = createHandler({
plugins: [
dynamoDbPlugins(),
logsPlugins(),
elasticSearch({ endpoint: `https://${process.env.ELASTIC_SEARCH_ENDPOINT}` }),
dbPlugins({
table: process.env.DB_TABLE,
driver: new DynamoDbDriver({
documentClient
})
}),
securityPlugins(),
i18nPlugins(),
i18nDynamoDbStorageOperations(),
i18nContentPlugins(),
fileManagerPlugins(),
fileManagerDynamoDbElasticStorageOperation(),
// Add File storage S3 plugin for API file manager.
fileManagerS3(),
adminUsersPlugins(),
securityAdminUsersDynamoDbStorageOperations(),
pageBuilderPlugins(),
pageBuilderDynamoDbElasticsearchPlugins(),
pageBuilderImportExportPlugins({
storageOperations: createStorageOperations({ documentClient })
}),
exportPagesCombinePlugins()
],
http: { debug }
});
84 changes: 84 additions & 0 deletions api/code/pageBuilder/exportPages/combine/src/security.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import tenancy from "@webiny/api-tenancy";
import security from "@webiny/api-security";
import personalAccessTokenAuthentication from "@webiny/api-security-admin-users/authentication/personalAccessToken";
import apiKeyAuthentication from "@webiny/api-security-admin-users/authentication/apiKey";
import userAuthorization from "@webiny/api-security-admin-users/authorization/user";
import apiKeyAuthorization from "@webiny/api-security-admin-users/authorization/apiKey";
import anonymousAuthorization from "@webiny/api-security-admin-users/authorization/anonymous";
import cognitoAuthentication from "@webiny/api-security-cognito-authentication";
import cognitoIdentityProvider from "@webiny/api-security-admin-users-cognito";

export default () => [
/**
* Security Tenancy API (context, users, groups, tenant links).
* This will setup the complete GraphQL schema to manage users, groups, access tokens,
* and provide you with a TenancyContext to access current Tenant data and DB operations.
*/
tenancy(),

/**
* Cognito IDP plugin (hooks for User CRUD methods).
* This plugin will perform CRUD operations on Cognito when you do something with the user
* via the UI or API. It's mostly to push changes to Cognito when they happen in your app.
*
* It also extends the GraphQL schema with things like "password", which we don't handle
* natively in our security, but Cognito will handle it for us.
*/
cognitoIdentityProvider({
region: process.env.COGNITO_REGION,
userPoolId: process.env.COGNITO_USER_POOL_ID
}),

/**
* Adds a context plugin to process `security-authentication` plugins.
* NOTE: this has to be registered *after* the "tenancy" plugins
* as some of the authentication plugins rely on tenancy context.
*/
security(),

/**
* Authentication plugin for Personal Access Tokens.
* PATs are directly linked to Users. We consider a token to be valid, if we manage to load
* a User who owns this particular token. The "identityType" is important, and it has to match
* the "identityType" configured in the authorization plugin later in this file.
*/
personalAccessTokenAuthentication({ identityType: "admin" }),

/**
* Authentication plugin for API Keys.
* API Keys are a standalone entity, and are not connected to users in any way.
* They identify a project, a 3rd party client, not the user.
* They are used for programmatic API access, CMS data import/export, etc.
*/
apiKeyAuthentication({ identityType: "api-key" }),

/**
* Cognito authentication plugin.
* This plugin will verify the JWT token against a provided User Pool.
*/
cognitoAuthentication({
region: process.env.COGNITO_REGION,
userPoolId: process.env.COGNITO_USER_POOL_ID,
identityType: "admin"
}),

/**
* Authorization plugin to fetch permissions for a verified API key.
* The "identityType" must match the authentication plugin used to load the identity.
*/
apiKeyAuthorization({ identityType: "api-key" }),

/**
* Authorization plugin to load user permissions for requested tenant.
* The authorization will only be performed on identities whose "type" matches
* the provided "identityType".
*/
userAuthorization({ identityType: "admin" }),

/**
* Authorization plugin to load permissions for anonymous requests.
* This allows you to control which API resources can be accessed publicly.
* The authorization is performed by loading permissions from the "anonymous" user group.
*/
anonymousAuthorization()
];
112 changes: 112 additions & 0 deletions api/code/pageBuilder/exportPages/combine/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"extends": "../../../../../tsconfig.json",
"include": ["./src"],
"references": [
{
"path": "../../../../../packages/api-elasticsearch"
},
{
"path": "../../../../../packages/api-i18n"
},
{
"path": "../../../../../packages/api-i18n-ddb"
},
{
"path": "../../../../../packages/api-security"
},
{
"path": "../../../../../packages/api-i18n-content"
},
{
"path": "../../../../../packages/api-page-builder"
},
{
"path": "../../../../../packages/api-page-builder-import-export"
},
{
"path": "../../../../../packages/api-tenancy"
},
{
"path": "../../../../../packages/api-security-admin-users"
},
{
"path": "../../../../../packages/api-security-admin-users-cognito"
},
{
"path": "../../../../../packages/api-security-admin-users-so-ddb"
},
{
"path": "../../../../../packages/api-file-manager"
},
{
"path": "../../../../../packages/api-file-manager-s3"
},
{
"path": "../../../../../packages/api-elasticsearch"
},
{
"path": "../../../../../packages/api-security-cognito-authentication"
},
{
"path": "../../../../../packages/db-dynamodb"
},
{
"path": "../../../../../packages/handler-aws"
},
{
"path": "../../../../../packages/handler-db"
},
{
"path": "../../../../../packages/handler-logs"
},
{
"path": "../../../../../packages/api-page-builder-so-ddb-es"
},
{
"path": "../../../../../packages/api-page-builder-import-export-so-ddb"
}
],
"compilerOptions": {
"paths": {
"~/*": ["./src/*"],
"@webiny/api-elasticsearch/*": ["../../../../../packages/api-elasticsearch/src/*"],
"@webiny/api-elasticsearch": ["../../../../../packages/api-elasticsearch/src"],
"@webiny/api-i18n/*": ["../../../../../packages/api-i18n/src/*"],
"@webiny/api-i18n": ["../../../../../packages/api-i18n/src"],
"@webiny/api-i18n-ddb/*": ["../../../../../packages/api-i18n-ddb/src/*"],
"@webiny/api-i18n-ddb": ["../../../../../packages/api-i18n-ddb/src"],
"@webiny/api-i18n-content/*": ["../../../../../packages/api-i18n-content/src/*"],
"@webiny/api-i18n-content": ["../../../../../packages/api-i18n-content/src"],
"@webiny/handler-aws/*": ["../../../../../packages/handler-aws/src/*"],
"@webiny/handler-aws": ["../../../../../packages/handler-aws/src"],
"@webiny/api-page-builder/*": ["../../../../../packages/api-page-builder/src/*"],
"@webiny/api-page-builder": ["../../../../../packages/api-page-builder/src"],
"@webiny/api-page-builder-import-export/*": [
"../../../../../packages/api-page-builder-import-export/src/*"
],
"@webiny/api-page-builder-import-export": [
"../../../../../packages/api-page-builder-import-export/src"
],
"@webiny/api-security/*": ["../../../../../packages/api-security/src/*"],
"@webiny/api-security": ["../../../../../packages/api-security/src"],
"@webiny/api-tenancy/*": ["../../../../../packages/api-tenancy/src/*"],
"@webiny/api-tenancy": ["../../../../../packages/api-tenancy/src"],
"@webiny/db-dynamodb/*": ["../../../../../packages/db-dynamodb/src/*"],
"@webiny/db-dynamodb": ["../../../../../packages/db-dynamodb/src"],
"@webiny/api-security-admin-users/*": [
"../../../../../packages/api-security-admin-users/src/*"
],
"@webiny/api-security-admin-users": ["../../../../../packages/api-security-admin-users/src"],
"@webiny/api-security-admin-users-cognito/*": [
"../../../../../packages/api-security-admin-users-cognito/src/*"
],
"@webiny/api-security-admin-users-cognito": [
"../../../../../packages/api-security-admin-users-cognito/src"
],
"@webiny/api-security-cognito-authentication": [
"../../../../../packages/api-security-cognito-authentication/src"
]
},
"baseUrl": "."
}
}
8 changes: 8 additions & 0 deletions api/code/pageBuilder/exportPages/combine/webiny.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { buildFunction, watchFunction } from "@webiny/project-utils";

export default {
commands: {
build: buildFunction,
watch: watchFunction
}
};

0 comments on commit eb30332

Please sign in to comment.