@canva/cli 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +2 -0
- package/cli.js +596 -574
- package/lib/cjs/index.cjs +2 -2
- package/lib/esm/index.mjs +2 -2
- package/lib/index.d.ts +2 -0
- package/package.json +7 -2
- package/templates/base/package.json +9 -8
- package/templates/base/styles/components.css +18 -0
- package/templates/common/.env.template +1 -1
- package/templates/common/jest.config.mjs +1 -1
- package/templates/dam/backend/server.ts +8 -0
- package/templates/dam/canva-app.json +9 -0
- package/templates/dam/package.json +10 -8
- package/templates/dam/src/index.tsx +3 -21
- package/templates/dam/src/intents/design_editor/index.tsx +25 -0
- package/templates/data_connector/README.md +1 -1
- package/templates/data_connector/package.json +9 -8
- package/templates/data_connector/src/api/data_sources/designs.tsx +1 -1
- package/templates/data_connector/src/api/data_sources/templates.tsx +1 -1
- package/templates/data_connector/src/components/header.tsx +1 -1
- package/templates/data_connector/src/index.tsx +2 -66
- package/templates/data_connector/src/{app.tsx → intents/data_connector/app.tsx} +3 -3
- package/templates/data_connector/src/{entrypoint.tsx → intents/data_connector/entrypoint.tsx} +5 -5
- package/templates/data_connector/src/{home.tsx → intents/data_connector/home.tsx} +1 -1
- package/templates/data_connector/src/intents/data_connector/index.tsx +56 -0
- package/templates/data_connector/src/pages/error.tsx +1 -1
- package/templates/data_connector/src/pages/login.tsx +1 -1
- package/templates/data_connector/src/routes/protected_route.tsx +1 -1
- package/templates/data_connector/src/routes/routes.tsx +3 -3
- package/templates/data_connector/styles/components.css +18 -0
- package/templates/gen_ai/backend/server.ts +17 -0
- package/templates/gen_ai/canva-app.json +5 -0
- package/templates/gen_ai/package.json +10 -8
- package/templates/gen_ai/src/api/api.ts +4 -0
- package/templates/gen_ai/src/components/footer.tsx +1 -1
- package/templates/gen_ai/src/components/loading_results.tsx +1 -1
- package/templates/gen_ai/src/components/prompt_input.tsx +1 -1
- package/templates/gen_ai/src/index.tsx +3 -14
- package/templates/gen_ai/src/{app.tsx → intents/design_editor/app.tsx} +3 -3
- package/templates/gen_ai/src/{home.tsx → intents/design_editor/home.tsx} +1 -1
- package/templates/gen_ai/src/intents/design_editor/index.tsx +17 -0
- package/templates/gen_ai/src/pages/error.tsx +1 -1
- package/templates/gen_ai/src/routes/routes.tsx +2 -2
- package/templates/gen_ai/styles/components.css +18 -0
- package/templates/hello_world/canva-app.json +5 -0
- package/templates/hello_world/package.json +10 -8
- package/templates/hello_world/src/index.tsx +3 -21
- package/templates/hello_world/src/{app.tsx → intents/design_editor/app.tsx} +26 -3
- package/templates/hello_world/src/intents/design_editor/index.tsx +25 -0
- package/templates/hello_world/src/{tests → intents/design_editor/tests}/app.tests.tsx +19 -13
- package/templates/hello_world/styles/components.css +18 -0
- package/templates/mls/README.md +81 -0
- package/templates/mls/canva-app.json +25 -0
- package/templates/mls/declarations/declarations.d.ts +29 -0
- package/templates/mls/eslint.config.mjs +14 -0
- package/templates/mls/jest.config.mjs +36 -0
- package/templates/mls/jest.setup.ts +37 -0
- package/templates/mls/package.json +117 -0
- package/templates/mls/scripts/copy_env.ts +13 -0
- package/templates/mls/scripts/ssl/ssl.ts +131 -0
- package/templates/mls/scripts/start/app_runner.ts +223 -0
- package/templates/mls/scripts/start/context.ts +171 -0
- package/templates/mls/scripts/start/start.ts +46 -0
- package/templates/mls/src/__tests__/app.tests.tsx +11 -0
- package/templates/mls/src/__tests__/office_selection_page.tests.tsx +72 -0
- package/templates/mls/src/__tests__/utils.tsx +19 -0
- package/templates/mls/src/adapter.ts +126 -0
- package/templates/mls/src/components/agent/agent_card.tsx +57 -0
- package/templates/mls/src/components/agent/agent_grid.tsx +37 -0
- package/templates/mls/src/components/agent/agent_list.tsx +17 -0
- package/templates/mls/src/components/agent/agent_search_filters.tsx +88 -0
- package/templates/mls/src/components/breadcrumb/breadcrumb.tsx +40 -0
- package/templates/mls/src/components/listing/listing_card.tsx +64 -0
- package/templates/mls/src/components/listing/listing_grid.tsx +37 -0
- package/templates/mls/src/components/listing/listing_list.tsx +21 -0
- package/templates/mls/src/components/listing/listing_search_filters.tsx +145 -0
- package/templates/mls/src/components/placeholders/placeholders.tsx +65 -0
- package/templates/mls/src/data.ts +359 -0
- package/templates/mls/src/index.tsx +4 -0
- package/templates/mls/src/intents/design_editor/app.tsx +44 -0
- package/templates/mls/src/intents/design_editor/index.tsx +25 -0
- package/templates/mls/src/pages/agent_details_page/agent_details_page.tsx +175 -0
- package/templates/mls/src/pages/list_page/agent_tab_panel.tsx +126 -0
- package/templates/mls/src/pages/list_page/list_page.tsx +67 -0
- package/templates/mls/src/pages/list_page/listing_tab_panel.tsx +135 -0
- package/templates/mls/src/pages/listing_details_page/listing_details_page.tsx +418 -0
- package/templates/mls/src/pages/loading_page/loading_page.tsx +152 -0
- package/templates/mls/src/pages/office_selection_page/office_selection_page.tsx +144 -0
- package/templates/mls/src/real_estate.type.ts +44 -0
- package/templates/mls/src/util/use_add_element.tsx +62 -0
- package/templates/mls/src/util/use_drag_element.tsx +68 -0
- package/templates/mls/styles/components.css +56 -0
- package/templates/mls/tsconfig.json +55 -0
- package/templates/mls/webpack.config.ts +254 -0
- package/templates/optional/AGENTS.md +80 -2
- package/templates/optional/CLAUDE.md +80 -2
- package/templates/base/backend/routers/oauth.ts +0 -393
- package/templates/base/utils/backend/bearer_middleware/bearer_middleware.ts +0 -99
- package/templates/base/utils/backend/bearer_middleware/index.ts +0 -1
- package/templates/base/utils/backend/bearer_middleware/tests/bearer_middleware.tests.ts +0 -192
- package/templates/base/utils/use_add_element.ts +0 -58
- package/templates/base/utils/use_feature_support.ts +0 -28
- package/templates/common/utils/backend/base_backend/create.ts +0 -104
- package/templates/common/utils/table_wrapper.ts +0 -520
- package/templates/common/utils/use_add_element.ts +0 -58
- package/templates/common/utils/use_feature_support.ts +0 -28
- package/templates/common/utils/use_overlay_hook.ts +0 -76
- package/templates/common/utils/use_selection_hook.ts +0 -37
- package/templates/gen_ai/backend/database/database.ts +0 -42
- package/templates/gen_ai/utils/backend/bearer_middleware/bearer_middleware.ts +0 -99
- package/templates/gen_ai/utils/backend/bearer_middleware/index.ts +0 -1
- package/templates/hello_world/utils/use_add_element.ts +0 -58
- package/templates/hello_world/utils/use_feature_support.ts +0 -28
- /package/templates/base/{utils/backend → backend}/base_backend/create.ts +0 -0
- /package/templates/base/{utils/backend → backend}/jwt_middleware/index.ts +0 -0
- /package/templates/base/{utils/backend → backend}/jwt_middleware/jwt_middleware.ts +0 -0
- /package/templates/dam/src/{adapter.ts → intents/design_editor/adapter.ts} +0 -0
- /package/templates/dam/src/{app.tsx → intents/design_editor/app.tsx} +0 -0
- /package/templates/dam/src/{config.ts → intents/design_editor/config.ts} +0 -0
- /package/templates/dam/src/{index.css → intents/design_editor/index.css} +0 -0
- /package/templates/data_connector/src/{paths.ts → routes/paths.ts} +0 -0
- /package/templates/gen_ai/src/{paths.ts → routes/paths.ts} +0 -0
- /package/templates/{common → gen_ai}/utils/backend/jwt_middleware/index.ts +0 -0
- /package/templates/{common → gen_ai}/utils/backend/jwt_middleware/jwt_middleware.ts +0 -0
- /package/templates/hello_world/src/{tests → intents/design_editor/tests}/__snapshots__/app.tests.tsx.snap +0 -0
|
@@ -1,22 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { createRoot } from "react-dom/client";
|
|
4
|
-
import { App } from "./app";
|
|
5
|
-
import "@canva/app-ui-kit/styles.css";
|
|
1
|
+
import { prepareDesignEditor } from "@canva/intents/design";
|
|
2
|
+
import designEditor from "./intents/design_editor";
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
function render() {
|
|
9
|
-
root.render(
|
|
10
|
-
<AppI18nProvider>
|
|
11
|
-
<AppUiProvider>
|
|
12
|
-
<App />
|
|
13
|
-
</AppUiProvider>
|
|
14
|
-
</AppI18nProvider>,
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
render();
|
|
19
|
-
|
|
20
|
-
if (module.hot) {
|
|
21
|
-
module.hot.accept("./app", render);
|
|
22
|
-
}
|
|
4
|
+
prepareDesignEditor(designEditor);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "@canva/app-ui-kit/styles.css";
|
|
2
|
+
import { AppI18nProvider } from "@canva/app-i18n-kit";
|
|
3
|
+
import { AppUiProvider } from "@canva/app-ui-kit";
|
|
4
|
+
import type { DesignEditorIntent } from "@canva/intents/design";
|
|
5
|
+
import { createRoot } from "react-dom/client";
|
|
6
|
+
import { App } from "./app";
|
|
7
|
+
|
|
8
|
+
async function render() {
|
|
9
|
+
const root = createRoot(document.getElementById("root") as Element);
|
|
10
|
+
|
|
11
|
+
root.render(
|
|
12
|
+
<AppI18nProvider>
|
|
13
|
+
<AppUiProvider>
|
|
14
|
+
<App />
|
|
15
|
+
</AppUiProvider>
|
|
16
|
+
</AppI18nProvider>,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const designEditor: DesignEditorIntent = { render };
|
|
21
|
+
export default designEditor;
|
|
22
|
+
|
|
23
|
+
if (module.hot) {
|
|
24
|
+
module.hot.accept("./app", render);
|
|
25
|
+
}
|
|
@@ -44,7 +44,7 @@ To run it and authenticate with the Canva Connect API via OAuth you must first c
|
|
|
44
44
|
### 0. Set up an App
|
|
45
45
|
|
|
46
46
|
- If not already handled by the Canva CLI, you need to create an app via the [Developer Portal](https://www.canva.com/developers/apps).
|
|
47
|
-
- On the **
|
|
47
|
+
- On the **Intents** page, enable the `Data Connector` intent.
|
|
48
48
|
|
|
49
49
|
### 1. Set up a Connect API Integration
|
|
50
50
|
|
|
@@ -19,16 +19,17 @@
|
|
|
19
19
|
"postinstall": "ts-node ./scripts/copy_env.ts"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@canva/app-
|
|
23
|
-
"@canva/app-
|
|
24
|
-
"@canva/
|
|
25
|
-
"@canva/
|
|
22
|
+
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
23
|
+
"@canva/app-i18n-kit": "^1.2.0",
|
|
24
|
+
"@canva/app-ui-kit": "^5.3.0",
|
|
25
|
+
"@canva/asset": "^2.2.2",
|
|
26
|
+
"@canva/design": "^2.7.5",
|
|
26
27
|
"@canva/error": "^2.1.0",
|
|
27
28
|
"@canva/intents": "^2.0.0",
|
|
28
29
|
"@canva/platform": "^2.2.0",
|
|
29
30
|
"@canva/user": "^2.1.1",
|
|
30
|
-
"react": "^19.2.
|
|
31
|
-
"react-dom": "^19.2.
|
|
31
|
+
"react": "^19.2.1",
|
|
32
|
+
"react-dom": "^19.2.1",
|
|
32
33
|
"react-error-boundary": "6.0.0",
|
|
33
34
|
"react-intl": "^7.1.11",
|
|
34
35
|
"react-router-dom": "7.8.2"
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"cssnano": "7.1.1",
|
|
61
62
|
"debug": "4.4.1",
|
|
62
63
|
"dotenv": "16.6.0",
|
|
63
|
-
"express": "4.
|
|
64
|
+
"express": "4.22.1",
|
|
64
65
|
"express-basic-auth": "1.2.1",
|
|
65
66
|
"jest": "29.7.0",
|
|
66
67
|
"jest-css-modules-transform": "4.4.2",
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
"jwks-rsa": "3.2.0",
|
|
70
71
|
"mini-css-extract-plugin": "2.9.4",
|
|
71
72
|
"node-fetch": "3.3.2",
|
|
72
|
-
"node-forge": "1.3.
|
|
73
|
+
"node-forge": "1.3.2",
|
|
73
74
|
"nodemon": "3.0.1",
|
|
74
75
|
"open": "8.4.2",
|
|
75
76
|
"postcss-loader": "8.1.1",
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { SearchFilter } from "src/components/inputs/search_filter";
|
|
14
14
|
import { SelectField } from "src/components/inputs/select_field";
|
|
15
15
|
import { useAppContext } from "src/context";
|
|
16
|
-
import { Paths } from "src/paths";
|
|
16
|
+
import { Paths } from "src/routes/paths";
|
|
17
17
|
import { dateCell, numberCell, stringCell } from "src/utils";
|
|
18
18
|
import type { CanvaItemResponse } from "../connect_client";
|
|
19
19
|
import { DataAPIError, DataSourceHandler } from "../data_source";
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { SearchFilter } from "src/components/inputs/search_filter";
|
|
19
19
|
import { SelectField } from "src/components/inputs/select_field";
|
|
20
20
|
import { useAppContext } from "src/context";
|
|
21
|
-
import { Paths } from "src/paths";
|
|
21
|
+
import { Paths } from "src/routes/paths";
|
|
22
22
|
import { dateCell, stringCell } from "src/utils";
|
|
23
23
|
import type { CanvaItemResponse } from "../connect_client";
|
|
24
24
|
import { DataAPIError, DataSourceHandler } from "../data_source";
|
|
@@ -1,68 +1,4 @@
|
|
|
1
|
-
import { Alert, AppUiProvider } from "@canva/app-ui-kit";
|
|
2
|
-
import type {
|
|
3
|
-
GetDataTableRequest,
|
|
4
|
-
GetDataTableResponse,
|
|
5
|
-
RenderSelectionUiRequest,
|
|
6
|
-
} from "@canva/intents/data";
|
|
7
1
|
import { prepareDataConnector } from "@canva/intents/data";
|
|
8
|
-
import
|
|
9
|
-
import { createRoot } from "react-dom/client";
|
|
10
|
-
import { buildDataTableResult, scope } from "./api";
|
|
11
|
-
import { App } from "./app";
|
|
12
|
-
import "@canva/app-ui-kit/styles.css";
|
|
2
|
+
import dataConnector from "./intents/data_connector";
|
|
13
3
|
|
|
14
|
-
|
|
15
|
-
prepareDataConnector({
|
|
16
|
-
/**
|
|
17
|
-
* Fetches structured data from an external source.
|
|
18
|
-
*
|
|
19
|
-
* This action is called in two scenarios:
|
|
20
|
-
*
|
|
21
|
-
* - During data selection to preview data before import (when {@link RenderSelectionUiRequest.updateDataRef} is called).
|
|
22
|
-
* - When refreshing previously imported data (when the user requests an update).
|
|
23
|
-
*
|
|
24
|
-
* @param params - Parameters for the data fetching operation.
|
|
25
|
-
* @returns A promise resolving to either a successful result with data or an error.
|
|
26
|
-
*/
|
|
27
|
-
getDataTable: async (
|
|
28
|
-
params: GetDataTableRequest,
|
|
29
|
-
): Promise<GetDataTableResponse> => {
|
|
30
|
-
const oauth = auth.initOauth();
|
|
31
|
-
const token = await oauth.getAccessToken({ scope });
|
|
32
|
-
return buildDataTableResult(params, token?.token);
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Renders a UI component for selecting and configuring data from external sources.
|
|
37
|
-
* This UI should allow users to browse data sources, apply filters, and select data.
|
|
38
|
-
* When selection is complete, the implementation must call the `updateDataRef`
|
|
39
|
-
* callback provided in the params to preview and confirm the data selection.
|
|
40
|
-
*
|
|
41
|
-
* @param request - parameters that provide context and configuration for the data selection UI.
|
|
42
|
-
* Contains invocation context, size limits, and the updateDataRef callback
|
|
43
|
-
*/
|
|
44
|
-
renderSelectionUi: async (request: RenderSelectionUiRequest) => {
|
|
45
|
-
function render() {
|
|
46
|
-
root.render(<App request={request} />);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
render();
|
|
50
|
-
|
|
51
|
-
if (module.hot) {
|
|
52
|
-
module.hot.accept("./app", render);
|
|
53
|
-
module.hot.accept("./api", render);
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// TODO: Fallback message if you have not turned on the data connector intent.
|
|
59
|
-
// You can remove this once your app is correctly configured.
|
|
60
|
-
root.render(
|
|
61
|
-
<AppUiProvider>
|
|
62
|
-
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
63
|
-
<Alert tone="critical">
|
|
64
|
-
If you're seeing this, you need to turn on the data connector intent in
|
|
65
|
-
the Developer Portal for this app.
|
|
66
|
-
</Alert>
|
|
67
|
-
</AppUiProvider>,
|
|
68
|
-
);
|
|
4
|
+
prepareDataConnector(dataConnector);
|
|
@@ -3,9 +3,9 @@ import { AppUiProvider } from "@canva/app-ui-kit";
|
|
|
3
3
|
import type { RenderSelectionUiRequest } from "@canva/intents/data";
|
|
4
4
|
import { ErrorBoundary } from "react-error-boundary";
|
|
5
5
|
import { createHashRouter, RouterProvider } from "react-router-dom";
|
|
6
|
-
import { ContextProvider } from "
|
|
7
|
-
import { ErrorPage } from "
|
|
8
|
-
import { routes } from "
|
|
6
|
+
import { ContextProvider } from "../../context";
|
|
7
|
+
import { ErrorPage } from "../../pages";
|
|
8
|
+
import { routes } from "../../routes";
|
|
9
9
|
|
|
10
10
|
export const App = ({ request }: { request: RenderSelectionUiRequest }) => (
|
|
11
11
|
<AppI18nProvider>
|
package/templates/data_connector/src/{entrypoint.tsx → intents/data_connector/entrypoint.tsx}
RENAMED
|
@@ -5,15 +5,15 @@ import type {
|
|
|
5
5
|
APIResponseItem,
|
|
6
6
|
DataSourceConfig,
|
|
7
7
|
DataSourceHandler,
|
|
8
|
-
} from "
|
|
9
|
-
import { DATA_SOURCES } from "
|
|
10
|
-
import { useAppContext } from "
|
|
11
|
-
import { Paths } from "
|
|
8
|
+
} from "../../api";
|
|
9
|
+
import { DATA_SOURCES } from "../../api/data_sources";
|
|
10
|
+
import { useAppContext } from "../../context";
|
|
11
|
+
import { Paths } from "../../routes/paths";
|
|
12
12
|
import {
|
|
13
13
|
isDataRefEmpty,
|
|
14
14
|
isLaunchedWithError,
|
|
15
15
|
isOutdatedSource,
|
|
16
|
-
} from "
|
|
16
|
+
} from "../../utils/data_params";
|
|
17
17
|
|
|
18
18
|
const parseDataSource = (source: string) => {
|
|
19
19
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Box, Rows } from "@canva/app-ui-kit";
|
|
2
2
|
import { Outlet } from "react-router-dom";
|
|
3
3
|
import * as styles from "styles/components.css";
|
|
4
|
-
import { AppError } from "
|
|
4
|
+
import { AppError } from "../../components";
|
|
5
5
|
|
|
6
6
|
export const Home = () => (
|
|
7
7
|
<div className={styles.scrollContainer}>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import "@canva/app-ui-kit/styles.css";
|
|
2
|
+
import type {
|
|
3
|
+
DataConnectorIntent,
|
|
4
|
+
GetDataTableRequest,
|
|
5
|
+
GetDataTableResponse,
|
|
6
|
+
RenderSelectionUiRequest,
|
|
7
|
+
} from "@canva/intents/data";
|
|
8
|
+
import { auth } from "@canva/user";
|
|
9
|
+
import { createRoot } from "react-dom/client";
|
|
10
|
+
import { buildDataTableResult, scope } from "../../api";
|
|
11
|
+
import { App } from "./app";
|
|
12
|
+
|
|
13
|
+
const dataConnector: DataConnectorIntent = {
|
|
14
|
+
/**
|
|
15
|
+
* Fetches structured data from an external source.
|
|
16
|
+
*
|
|
17
|
+
* This action is called in two scenarios:
|
|
18
|
+
*
|
|
19
|
+
* - During data selection to preview data before import (when {@link RenderSelectionUiRequest.updateDataRef} is called).
|
|
20
|
+
* - When refreshing previously imported data (when the user requests an update).
|
|
21
|
+
*
|
|
22
|
+
* @param params - Parameters for the data fetching operation.
|
|
23
|
+
* @returns A promise resolving to either a successful result with data or an error.
|
|
24
|
+
*/
|
|
25
|
+
getDataTable: async (
|
|
26
|
+
params: GetDataTableRequest,
|
|
27
|
+
): Promise<GetDataTableResponse> => {
|
|
28
|
+
const oauth = auth.initOauth();
|
|
29
|
+
const token = await oauth.getAccessToken({ scope });
|
|
30
|
+
return buildDataTableResult(params, token?.token);
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Renders a UI component for selecting and configuring data from external sources.
|
|
35
|
+
* This UI should allow users to browse data sources, apply filters, and select data.
|
|
36
|
+
* When selection is complete, the implementation must call the `updateDataRef`
|
|
37
|
+
* callback provided in the params to preview and confirm the data selection.
|
|
38
|
+
*
|
|
39
|
+
* @param request - parameters that provide context and configuration for the data selection UI.
|
|
40
|
+
* Contains invocation context, size limits, and the updateDataRef callback
|
|
41
|
+
*/
|
|
42
|
+
renderSelectionUi: async (request: RenderSelectionUiRequest) => {
|
|
43
|
+
function render() {
|
|
44
|
+
const root = createRoot(document.getElementById("root") as Element);
|
|
45
|
+
root.render(<App request={request} />);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
render();
|
|
49
|
+
|
|
50
|
+
if (module.hot) {
|
|
51
|
+
module.hot.accept("./app", render);
|
|
52
|
+
module.hot.accept("../../api", render);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
export default dataConnector;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Button, Rows, Text } from "@canva/app-ui-kit";
|
|
2
2
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
3
3
|
import { useNavigate } from "react-router-dom";
|
|
4
|
-
import { Paths } from "src/paths";
|
|
4
|
+
import { Paths } from "src/routes/paths";
|
|
5
5
|
import * as styles from "styles/components.css";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -11,7 +11,7 @@ import { defineMessages, FormattedMessage, useIntl } from "react-intl";
|
|
|
11
11
|
import { useNavigate } from "react-router-dom";
|
|
12
12
|
import { scope } from "src/api";
|
|
13
13
|
import { Header } from "src/components";
|
|
14
|
-
import { Paths } from "src/paths";
|
|
14
|
+
import { Paths } from "src/routes/paths";
|
|
15
15
|
import * as styles from "styles/components.css";
|
|
16
16
|
import { useAppContext } from "../context";
|
|
17
17
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { useNavigate } from "react-router-dom";
|
|
4
|
-
import { Paths } from "src/paths";
|
|
4
|
+
import { Paths } from "src/routes/paths";
|
|
5
5
|
import { useAppContext } from "../context";
|
|
6
6
|
|
|
7
7
|
interface ProtectedRouteProps {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Entrypoint } from "src/entrypoint";
|
|
2
|
-
import { Home } from "src/home";
|
|
1
|
+
import { Entrypoint } from "src/intents/data_connector/entrypoint";
|
|
2
|
+
import { Home } from "src/intents/data_connector/home";
|
|
3
3
|
import { DataSourceConfig } from "src/pages/data_source_config";
|
|
4
4
|
import { ErrorPage } from "src/pages/error";
|
|
5
5
|
import { Login } from "src/pages/login";
|
|
6
6
|
import { SelectSource } from "src/pages/select_source";
|
|
7
|
-
import { Paths } from "src/paths";
|
|
7
|
+
import { Paths } from "src/routes/paths";
|
|
8
8
|
import { ProtectedRoute } from "./protected_route";
|
|
9
9
|
|
|
10
10
|
export const routes = [
|
|
@@ -36,3 +36,21 @@
|
|
|
36
36
|
.scrollContainer:focus-within::-webkit-scrollbar-thumb {
|
|
37
37
|
visibility: visible;
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/* Main container for the content publisher preview UI */
|
|
41
|
+
.previewContainer {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Wrapper for the content publisher post preview */
|
|
51
|
+
.previewWrapper {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
width: calc(400px + 32px + 2px); /* Image width + padding + border */
|
|
56
|
+
}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import cors from "cors";
|
|
2
2
|
import express from "express";
|
|
3
3
|
import { createBaseServer } from "../utils/backend/base_backend/create";
|
|
4
|
+
import { createJwtMiddleware } from "../utils/backend/jwt_middleware/index";
|
|
4
5
|
import { createImageRouter } from "./routers/image";
|
|
5
6
|
|
|
6
7
|
async function main() {
|
|
8
|
+
// TODO: Set the CANVA_APP_ID environment variable in the project's .env file
|
|
9
|
+
const APP_ID = process.env.CANVA_APP_ID;
|
|
10
|
+
|
|
11
|
+
if (!APP_ID) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`The CANVA_APP_ID environment variable is undefined. Set the variable in the project's .env file.`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
7
17
|
const router = express.Router();
|
|
8
18
|
|
|
9
19
|
/**
|
|
@@ -36,6 +46,13 @@ async function main() {
|
|
|
36
46
|
*/
|
|
37
47
|
router.use(cors());
|
|
38
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Initialize JWT middleware to verify Canva user tokens
|
|
51
|
+
* This middleware validates tokens sent from the frontend and extracts user information
|
|
52
|
+
*/
|
|
53
|
+
const jwtMiddleware = createJwtMiddleware(APP_ID);
|
|
54
|
+
router.use(jwtMiddleware);
|
|
55
|
+
|
|
39
56
|
/**
|
|
40
57
|
* Add routes for image generation.
|
|
41
58
|
*/
|
|
@@ -18,19 +18,21 @@
|
|
|
18
18
|
"postinstall": "ts-node ./scripts/copy_env.ts"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@canva/app-
|
|
22
|
-
"@canva/app-
|
|
23
|
-
"@canva/
|
|
24
|
-
"@canva/
|
|
21
|
+
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
22
|
+
"@canva/app-i18n-kit": "^1.2.0",
|
|
23
|
+
"@canva/app-ui-kit": "^5.3.0",
|
|
24
|
+
"@canva/asset": "^2.2.2",
|
|
25
|
+
"@canva/design": "^2.7.5",
|
|
25
26
|
"@canva/error": "^2.1.0",
|
|
27
|
+
"@canva/intents": "^2.0.0",
|
|
26
28
|
"@canva/platform": "^2.2.0",
|
|
27
29
|
"@canva/user": "^2.1.1",
|
|
28
30
|
"cookie-parser": "1.4.7",
|
|
29
31
|
"cors": "2.8.5",
|
|
30
32
|
"html-react-parser": "5.2.6",
|
|
31
33
|
"obscenity": "0.4.4",
|
|
32
|
-
"react": "^19.2.
|
|
33
|
-
"react-dom": "^19.2.
|
|
34
|
+
"react": "^19.2.1",
|
|
35
|
+
"react-dom": "^19.2.1",
|
|
34
36
|
"react-error-boundary": "6.0.0",
|
|
35
37
|
"react-intl": "^7.1.11",
|
|
36
38
|
"react-router-dom": "7.8.2"
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
"debug": "4.4.1",
|
|
67
69
|
"dotenv": "16.6.0",
|
|
68
70
|
"exponential-backoff": "3.1.2",
|
|
69
|
-
"express": "4.
|
|
71
|
+
"express": "4.22.1",
|
|
70
72
|
"express-basic-auth": "1.2.1",
|
|
71
73
|
"jest": "29.7.0",
|
|
72
74
|
"jest-css-modules-transform": "4.4.2",
|
|
@@ -75,7 +77,7 @@
|
|
|
75
77
|
"jwks-rsa": "3.2.0",
|
|
76
78
|
"mini-css-extract-plugin": "2.9.4",
|
|
77
79
|
"node-fetch": "3.3.2",
|
|
78
|
-
"node-forge": "1.3.
|
|
80
|
+
"node-forge": "1.3.2",
|
|
79
81
|
"nodemon": "3.0.1",
|
|
80
82
|
"open": "8.4.2",
|
|
81
83
|
"postcss-loader": "8.1.1",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { auth } from "@canva/user";
|
|
1
2
|
import { POLLING_INTERVAL_IN_SECONDS } from "src/config";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -167,8 +168,11 @@ export const purchaseCredits = async (): Promise<RemainingCreditsResult> => {
|
|
|
167
168
|
* @returns {Promise<Object>} - A promise that resolves to the response body.
|
|
168
169
|
*/
|
|
169
170
|
const sendRequest = async <T>(url: URL, options?: RequestInit): Promise<T> => {
|
|
171
|
+
const userToken = await auth.getCanvaUserToken();
|
|
172
|
+
|
|
170
173
|
const res = await fetch(url, {
|
|
171
174
|
headers: {
|
|
175
|
+
Authorization: `Bearer ${userToken}`,
|
|
172
176
|
...options?.headers,
|
|
173
177
|
},
|
|
174
178
|
...options,
|
|
@@ -6,7 +6,7 @@ import { purchaseCredits, queueImageGeneration } from "src/api";
|
|
|
6
6
|
import { RemainingCredits } from "src/components";
|
|
7
7
|
import { NUMBER_OF_IMAGES_TO_GENERATE } from "src/config";
|
|
8
8
|
import { useAppContext } from "src/context";
|
|
9
|
-
import { Paths } from "src/paths";
|
|
9
|
+
import { Paths } from "src/routes/paths";
|
|
10
10
|
import { getObsceneWords } from "src/utils";
|
|
11
11
|
import { FooterMessages as Messages } from "./footer.messages";
|
|
12
12
|
|
|
@@ -12,7 +12,7 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|
|
12
12
|
import { useNavigate } from "react-router-dom";
|
|
13
13
|
import { cancelImageGenerationJob, getImageGenerationJobStatus } from "src/api";
|
|
14
14
|
import { useAppContext } from "src/context";
|
|
15
|
-
import { Paths } from "src/paths";
|
|
15
|
+
import { Paths } from "src/routes/paths";
|
|
16
16
|
|
|
17
17
|
const INTERVAL_DURATION_IN_MS = 100;
|
|
18
18
|
const TOTAL_PROGRESS_PERCENTAGE = 100;
|
|
@@ -9,7 +9,7 @@ import { useState } from "react";
|
|
|
9
9
|
import { useIntl } from "react-intl";
|
|
10
10
|
import { useLocation } from "react-router-dom";
|
|
11
11
|
import { useAppContext } from "src/context";
|
|
12
|
-
import { Paths } from "src/paths";
|
|
12
|
+
import { Paths } from "src/routes/paths";
|
|
13
13
|
import { PromptInputMessages as Messages } from "./prompt_input.messages";
|
|
14
14
|
|
|
15
15
|
// @TODO: Adjust according to your specific requirements.
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "
|
|
3
|
-
import { App } from "./app";
|
|
1
|
+
import { prepareDesignEditor } from "@canva/intents/design";
|
|
2
|
+
import designEditor from "./intents/design_editor";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function render() {
|
|
8
|
-
root.render(<App />);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
render();
|
|
12
|
-
|
|
13
|
-
if (module.hot) {
|
|
14
|
-
module.hot.accept("./app", render);
|
|
15
|
-
}
|
|
4
|
+
prepareDesignEditor(designEditor);
|
|
@@ -2,9 +2,9 @@ import { AppI18nProvider } from "@canva/app-i18n-kit";
|
|
|
2
2
|
import { AppUiProvider } from "@canva/app-ui-kit";
|
|
3
3
|
import { ErrorBoundary } from "react-error-boundary";
|
|
4
4
|
import { createHashRouter, RouterProvider } from "react-router-dom";
|
|
5
|
-
import { ContextProvider } from "
|
|
6
|
-
import { ErrorPage } from "
|
|
7
|
-
import { routes } from "
|
|
5
|
+
import { ContextProvider } from "../../context";
|
|
6
|
+
import { ErrorPage } from "../../pages";
|
|
7
|
+
import { routes } from "../../routes";
|
|
8
8
|
|
|
9
9
|
export const App = () => (
|
|
10
10
|
<AppI18nProvider>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Rows } from "@canva/app-ui-kit";
|
|
2
2
|
import { Outlet } from "react-router-dom";
|
|
3
3
|
import * as styles from "styles/components.css";
|
|
4
|
-
import { Footer } from "
|
|
4
|
+
import { Footer } from "../../components";
|
|
5
5
|
|
|
6
6
|
export const Home = () => (
|
|
7
7
|
<div className={styles.scrollContainer}>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "@canva/app-ui-kit/styles.css";
|
|
2
|
+
import type { DesignEditorIntent } from "@canva/intents/design";
|
|
3
|
+
import { createRoot } from "react-dom/client";
|
|
4
|
+
import { App } from "./app";
|
|
5
|
+
|
|
6
|
+
async function render() {
|
|
7
|
+
const root = createRoot(document.getElementById("root") as Element);
|
|
8
|
+
|
|
9
|
+
root.render(<App />);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const designEditor: DesignEditorIntent = { render };
|
|
13
|
+
export default designEditor;
|
|
14
|
+
|
|
15
|
+
if (module.hot) {
|
|
16
|
+
module.hot.accept("./app", render);
|
|
17
|
+
}
|
|
@@ -2,7 +2,7 @@ import { Button, Rows, Text } from "@canva/app-ui-kit";
|
|
|
2
2
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
3
3
|
import { useNavigate } from "react-router-dom";
|
|
4
4
|
import { useAppContext } from "src/context";
|
|
5
|
-
import { Paths } from "src/paths";
|
|
5
|
+
import { Paths } from "src/routes/paths";
|
|
6
6
|
import * as styles from "styles/components.css";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Home } from "src/home";
|
|
1
|
+
import { Home } from "src/intents/design_editor/home";
|
|
2
2
|
import { ErrorPage } from "src/pages/error";
|
|
3
3
|
import { GeneratePage } from "src/pages/generate";
|
|
4
4
|
import { ResultsPage } from "src/pages/results";
|
|
5
|
-
import { Paths } from "src/paths";
|
|
5
|
+
import { Paths } from "src/routes/paths";
|
|
6
6
|
|
|
7
7
|
export const routes = [
|
|
8
8
|
{
|
|
@@ -36,3 +36,21 @@
|
|
|
36
36
|
.scrollContainer:focus-within::-webkit-scrollbar-thumb {
|
|
37
37
|
visibility: visible;
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/* Main container for the content publisher preview UI */
|
|
41
|
+
.previewContainer {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Wrapper for the content publisher post preview */
|
|
51
|
+
.previewWrapper {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
width: calc(400px + 32px + 2px); /* Image width + padding + border */
|
|
56
|
+
}
|