Skip to content
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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
/tests/commands/deployment/ @celonis/astro @celonis/studio-platform
/src/commands/action-flows/ @celonis/process-automation
/tests/commands/action-flows/ @celonis/process-automation
/src/commands/bookmarks/ @celonis/studio-platform
/tests/commands/bookmarks/ @celonis/studio-platform
/src/commands/analysis/ @celonis/process-analytics
/src/commands/cpm4/ @celonis/cpm4
/src/commands/data-pipeline/ @Dusan-r @IvanGandacov @EktaCelonis @gorasoCelonis
Expand Down
14 changes: 10 additions & 4 deletions docs/command-graph.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@
{ id: "area_analyze", label: "analyze", group: "area", path: "analyze",
description: "Analyze action flows and return its dependencies", options: ["-h, --help"] },
{ id: "area_export", label: "export", group: "area", path: "export",
description: "Export resource: action flow or data pool", options: ["-h, --help"] },
description: "Export resource: action flow, data pool, or bookmarks", options: ["-h, --help"] },
{ id: "area_import", label: "import", group: "area", path: "import",
description: "Import resource: action flow or data pool", options: ["-h, --help"] },
description: "Import resource: action flow, data pool, or bookmarks", options: ["-h, --help"] },
{ id: "area_pull", label: "pull", group: "area", path: "pull",
description: "Pull resource: skill, bookmark, view bookmark, data pool or asset", options: ["-h, --help"] },
{ id: "area_push", label: "push", group: "area", path: "push",
Expand Down Expand Up @@ -211,6 +211,9 @@
{ id: "export_data_pool", label: "data-pool", group: "command", path: "export data-pool",
description: "Command to export a data pool",
options: ["-p, --profile <profile>", "--id <id>", "--outputToJsonFile", "-h, --help"] },
{ id: "export_bookmarks", label: "bookmarks", group: "command", path: "export bookmarks",
description: "Export bookmarks for a package",
options: ["-p, --profile <profile>", "--packageKey <packageKey>", "-f, --file <file>", "-h, --help"] },

// import
{ id: "import_action_flows", label: "action-flows", group: "command", path: "import action-flows",
Expand All @@ -219,6 +222,9 @@
{ id: "import_data_pools", label: "data-pools", group: "command", path: "import data-pools",
description: "Command to batch import multiple data pools with their objects and dependencies",
options: ["-p, --profile <profile>", "-f, --jsonFile <file>", "--outputToJsonFile", "-h, --help"] },
{ id: "import_bookmarks", label: "bookmarks", group: "command", path: "import bookmarks",
description: "Import bookmarks into a package",
options: ["-p, --profile <profile>", "--packageKey <packageKey>", "-f, --file <file>", "-h, --help"] },

// pull
{ id: "pull_skill", label: "skill", group: "command", path: "pull skill",
Expand Down Expand Up @@ -479,9 +485,9 @@

["area_analyze","analyze_action_flows"],

["area_export","export_action_flows"],["area_export","export_data_pool"],
["area_export","export_action_flows"],["area_export","export_data_pool"],["area_export","export_bookmarks"],

["area_import","import_action_flows"],["area_import","import_data_pools"],
["area_import","import_action_flows"],["area_import","import_data_pools"],["area_import","import_bookmarks"],

["area_pull","pull_skill"],["area_pull","pull_bookmarks"],["area_pull","pull_data_pool"],
["area_pull","pull_asset"],["area_pull","pull_package"],["area_pull","pull_view_bookmarks"],
Expand Down
25 changes: 25 additions & 0 deletions docs/user-guide/bookmark-commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Bookmark Commands

## Export Bookmarks

Export all bookmarks for a package. The exported file can then be imported into another team using the `import bookmarks` command.

```
content-cli export bookmarks -p <profile> --packageKey <packageKey>
```

By default, the export is saved to `bookmarks-<packageKey>.json` in the current directory. Use `-f` to specify a custom output path:

```
content-cli export bookmarks -p <profile> --packageKey <packageKey> -f my-bookmarks.json
```

## Import Bookmarks

Import bookmarks into a package from a previously exported JSON file.

```
content-cli import bookmarks -p <profile> --packageKey <packageKey> -f bookmarks-<packageKey>.json
```

The import result is printed to the console showing the status of each entry (CREATED or SKIPPED).
1 change: 1 addition & 0 deletions docs/user-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Content CLI organizes its commands into groups by area. Each group covers a spec
| [Asset Registry Commands](./asset-registry-commands.md) | Discover registered asset types and their service descriptors |
| [Data Pool Commands](./data-pool-commands.md) | Export and import Data Pools with their dependencies |
| [Action Flow Commands](./action-flow-commands.md) | Analyze and export/import Action Flows and their dependencies |
| [Bookmark Commands](./bookmark-commands.md) | Export and import bookmarks for packages |
1 change: 1 addition & 0 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ nav:
- Asset Registry Commands: './user-guide/asset-registry-commands.md'
- Data Pool Commands: './user-guide/data-pool-commands.md'
- Action Flow Commands: './user-guide/action-flow-commands.md'
- Bookmark Commands: './user-guide/bookmark-commands.md'
- Development:
- Architecture: './internal-architecture.md'
- How to Add a Command: './how-to-add-command.md'
Expand Down
29 changes: 29 additions & 0 deletions src/commands/bookmarks/bookmarks-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HttpClient } from "../../core/http/http-client";
import { Context } from "../../core/command/cli-context";
import { FatalError } from "../../core/utils/logger";
import { BookmarksExport, BookmarksImportRequest, BookmarksImportResult } from "./bookmarks.interfaces";

export class BookmarksApi {

private readonly httpClient: () => HttpClient;

constructor(context: Context) {
this.httpClient = () => context.httpClient;
}

public async exportBookmarks(packageKey: string): Promise<BookmarksExport> {
try {
return await this.httpClient().get(`/package-manager/api/packages/${encodeURIComponent(packageKey)}/bookmarks/export`);
} catch (e) {
throw new FatalError(`Problem exporting bookmarks for package ${packageKey}: ${e}`);
}
}

public async importBookmarks(packageKey: string, payload: BookmarksImportRequest): Promise<BookmarksImportResult> {
try {
return await this.httpClient().post(`/package-manager/api/packages/${encodeURIComponent(packageKey)}/bookmarks/import`, payload);
} catch (e) {
throw new FatalError(`Problem importing bookmarks for package ${packageKey}: ${e}`);
}
}
}
27 changes: 27 additions & 0 deletions src/commands/bookmarks/bookmarks-command.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Context } from "../../core/command/cli-context";
import { BookmarksApi } from "./bookmarks-api";
import { fileService, FileService } from "../../core/utils/file-service";
import { logger } from "../../core/utils/logger";

export class BookmarksCommandService {

private readonly bookmarksApi: BookmarksApi;

constructor(context: Context) {
this.bookmarksApi = new BookmarksApi(context);
}

public async exportBookmarks(packageKey: string, file?: string): Promise<void> {
const exportData = await this.bookmarksApi.exportBookmarks(packageKey);

const fileName = file ?? `bookmarks-${packageKey}.json`;
fileService.writeToFileWithGivenName(JSON.stringify(exportData, null, 4), fileName);
Comment thread
tneum-celonis marked this conversation as resolved.
logger.info(FileService.fileDownloadedMessage + fileName);
}

public async importBookmarks(packageKey: string, file: string): Promise<void> {
const payload = fileService.readFileToJson(file);
Comment thread
tneum-celonis marked this conversation as resolved.
const result = await this.bookmarksApi.importBookmarks(packageKey, payload);
logger.info(`Bookmarks imported successfully: ${JSON.stringify(result, null, 4)}`);
}
}
40 changes: 40 additions & 0 deletions src/commands/bookmarks/bookmarks.interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export interface BookmarkEntry {
assetKey: string;
assetType: string;
bookmark: BookmarkDetails;
preference: BookmarkPreference;
}

export interface BookmarkDetails {
name: string;
ownerId: string;
sharedByLink: boolean;
published: boolean;
}

export interface BookmarkPreference {
configuration: string;
shareable: boolean;
mode: string;
userId: string;
}

export interface BookmarksExport {
packageKey: string;
entries: BookmarkEntry[];
}

export interface BookmarksImportRequest {
entries: BookmarkEntry[];
}

export interface BookmarksImportResultEntry {
assetKey: string;
status: string;
reason: string | null;
}

export interface BookmarksImportResult {
packageKey: string;
entries: BookmarksImportResultEntry[];
}
33 changes: 33 additions & 0 deletions src/commands/bookmarks/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Configurator, IModule } from "../../core/command/module-handler";
import { Context } from "../../core/command/cli-context";
import { Command, OptionValues } from "commander";
import { BookmarksCommandService } from "./bookmarks-command.service";

class Module extends IModule {

public register(context: Context, configurator: Configurator): void {
const exportCommand = configurator.command("export");
exportCommand.command("bookmarks")
.description("Export bookmarks for a package")
.requiredOption("--packageKey <packageKey>", "Key of the package to export bookmarks from")
.option("-f, --file <file>", "Output file path (defaults to bookmarks-<packageKey>.json)")
.action(this.exportBookmarks);

const importCommand = configurator.command("import");
importCommand.command("bookmarks")
.description("Import bookmarks into a package")
.requiredOption("--packageKey <packageKey>", "Key of the package to import bookmarks into")
.requiredOption("-f, --file <file>", "Bookmarks JSON file to import")
.action(this.importBookmarks);
}

private async exportBookmarks(context: Context, _command: Command, options: OptionValues): Promise<void> {
await new BookmarksCommandService(context).exportBookmarks(options.packageKey, options.file);
}

private async importBookmarks(context: Context, _command: Command, options: OptionValues): Promise<void> {
await new BookmarksCommandService(context).importBookmarks(options.packageKey, options.file);
}
}

export = Module;
Loading
Loading