obsidian-confluence 5.6.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/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Obsidian Confluence Integration Plugin
2
+
3
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/markdown-confluence/markdown-confluence/badge)](https://api.securityscorecards.dev/projects/github.com/markdown-confluence/markdown-confluence)
4
+
5
+ Copyright (c) 2022 Atlassian Pty Ltd
6
+
7
+ Copyright (c) 2022 Atlassian US, Inc.
8
+
9
+ `Obsidian Confluence Integration Plugin` is an open-source plugin for [Obsidian.md](https://obsidian.md/) that allows you to publish markdown content from Obsidian to [Atlassian Confluence](https://www.atlassian.com/software/confluence). It supports [Obsidian markdown extensions](https://help.obsidian.md/How+to/Format+your+notes) for richer content and includes a CLI for pushing markdown files from the command line. Currently, the plugin only supports Atlassian Cloud instances.
10
+
11
+ ## Features
12
+
13
+ - Publish Obsidian notes to Atlassian Confluence
14
+ - Support for Obsidian markdown extensions
15
+ - CLI for pushing markdown files from disk
16
+ - Commands and ribbon icon for easy access
17
+
18
+ ## Issues
19
+ Please log issues to https://github.com/markdown-confluence/markdown-confluence/issues as this is where the code is being developed.
20
+
21
+ ## Getting Started
22
+
23
+ 1. Install the `confluence-integration` plugin from Obsidian's community plugins browser.
24
+ 2. Open the plugin settings and configure the following fields:
25
+
26
+ - `Confluence Base URL`: The base URL of your Atlassian Confluence instance (e.g., `https://your-domain.atlassian.net`)
27
+ - `Confluence Parent Id`: The Confluence page ID where your notes will be published as child pages
28
+ - `Atlassian User Name`: Your Atlassian account's email address
29
+ - `Atlassian API Token`: Your Atlassian API token. You can generate one from your [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens).
30
+ - `Folder To Publish`: The name of the folder in Obsidian containing the notes you want to publish (default: "Confluence Pages")
31
+
32
+ ![Settings](./docs/screenshots/settings.png)
33
+
34
+ ## Usage
35
+
36
+ ### Ribbon Icon
37
+
38
+ Click the cloud icon in the ribbon to publish the notes from the configured folder to Confluence.
39
+
40
+ ![Ribbon icon](./docs/screenshots/ribbon.png)
41
+
42
+
43
+ ### Commands
44
+
45
+ Use the command palette (`Ctrl/Cmd + P`) to execute the "Publish All to Confluence" command, which publishes all the notes from the configured folder to Confluence.
46
+
47
+ ![Commands](./docs/screenshots/commands.png)
48
+
49
+ ### connie-publish Frontmatter
50
+
51
+ To publish pages outside the `folderToPublish`, add the `connie-publish` YAML frontmatter to your notes:
52
+
53
+ ```yaml
54
+ ---
55
+ connie-publish: true
56
+ ---
57
+ ```
58
+
59
+ ### Example Workflow
60
+ 1. Install and configure the `confluence-integration` plugin.
61
+ 2. Create a folder in your Obsidian vault named "Confluence Pages" (or the folder name you specified in the settings).
62
+ 3. Add notes to this folder or add the connie-publish frontmatter to other notes.
63
+ 4. Click the cloud icon in the ribbon or use the "Publish All to Confluence" command to publish your notes to Confluence.
64
+
65
+ ### Contributing
66
+ Contributions are welcome! If you have a feature request, bug report, or want to improve the plugin, please open an issue or submit a pull request on the GitHub repository.
67
+
68
+ ### License
69
+ This project is licensed under the [Apache 2.0](https://github.com/markdown-confluence/markdown-confluence/blob/main/LICENSE) License.
70
+
71
+ ## Disclaimer:
72
+ The Apache license is only applicable to the Obsidian Confluence Integration (“Integration“), not to any third parties' services, websites, content or platforms that this Integration may enable you to connect with. In another word, there is no license granted to you by the above identified licensor(s) to access any third-party services, websites, content, or platforms. You are solely responsible for obtaining licenses from such third parties to use and access their services and to comply with their license terms. Please do not disclose any passwords, credentials, or tokens to any third-party service in your contribution to this Obsidian Confluence Integration project.”
Binary file
Binary file
Binary file
@@ -0,0 +1,55 @@
1
+ import esbuild from "esbuild";
2
+ import process from "process";
3
+ import builtins from 'builtin-modules'
4
+ import { writeFileSync } from 'fs';
5
+
6
+
7
+ const banner =
8
+ `/*
9
+ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
10
+ if you want to view the source, please visit the github repository of this plugin
11
+ */
12
+ `;
13
+
14
+ const prod = (process.argv[2] === 'production');
15
+
16
+ const buildConfig = {
17
+ banner: {
18
+ js: banner,
19
+ },
20
+ entryPoints: ['src/main.ts'],
21
+ bundle: true,
22
+ external: [
23
+ 'obsidian',
24
+ 'electron',
25
+ '@codemirror/autocomplete',
26
+ '@codemirror/collab',
27
+ '@codemirror/commands',
28
+ '@codemirror/language',
29
+ '@codemirror/lint',
30
+ '@codemirror/search',
31
+ '@codemirror/state',
32
+ '@codemirror/view',
33
+ '@lezer/common',
34
+ '@lezer/highlight',
35
+ '@lezer/lr',
36
+ ...builtins
37
+ ],
38
+ format: 'cjs',
39
+ target: 'chrome106',
40
+ logLevel: "info",
41
+ sourcemap: prod ? false : 'inline',
42
+ treeShaking: true,
43
+ outdir: prod ? 'dist' : '../../dev-vault/.obsidian/plugins/obsidian-confluence',
44
+ mainFields: ['module', 'main'],
45
+ minify: true,
46
+ metafile: true,
47
+ };
48
+
49
+ if (prod) {
50
+ const buildResult = await esbuild.build(buildConfig);
51
+ writeFileSync("./dist/meta.json", JSON.stringify(buildResult.metafile));
52
+ } else {
53
+ const context = await esbuild.context(buildConfig);
54
+ await context.watch();
55
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "obsidian-confluence",
3
+ "version": "5.6.0",
4
+ "description": "This library allows you to publish your notes to Confluence",
5
+ "main": "main.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "node esbuild.config.mjs",
9
+ "build": "tsc && node esbuild.config.mjs production",
10
+ "fmt": "npx prettier --write src/",
11
+ "lint": "eslint --ignore-path ../../.eslintignore --ext .jsx,tsx,.js,.ts src/",
12
+ "prettier-check": "npx prettier --check src/"
13
+ },
14
+ "keywords": [],
15
+ "author": "andymac4182",
16
+ "license": "Apache 2.0",
17
+ "devDependencies": {
18
+ "@types/mime-types": "^2.1.1",
19
+ "@types/react-dom": "^18.0.11",
20
+ "obsidian": "1.1.1"
21
+ },
22
+ "dependencies": {
23
+ "confluence.js": "^1.6.3",
24
+ "mime-types": "^2.1.35",
25
+ "react": "^16.14.0",
26
+ "react-dom": "^16.14.0",
27
+ "md-confluence-lib": "5.6.0",
28
+ "md-confluence-mermaid-electron-renderer": "5.6.0"
29
+ },
30
+ "resolutions": {
31
+ "prosemirror-model": "1.14.3"
32
+ }
33
+ }
@@ -0,0 +1,160 @@
1
+ import { Modal, App } from "obsidian";
2
+ import ReactDOM from "react-dom";
3
+ import React, { useState } from "react";
4
+ import { UploadAdfFileResult } from "md-confluence-lib";
5
+
6
+ export interface FailedFile {
7
+ fileName: string;
8
+ reason: string;
9
+ }
10
+
11
+ export interface UploadResults {
12
+ errorMessage: string | null;
13
+ failedFiles: FailedFile[];
14
+ filesUploadResult: UploadAdfFileResult[];
15
+ }
16
+
17
+ export interface UploadResultsProps {
18
+ uploadResults: UploadResults;
19
+ }
20
+
21
+ const CompletedView: React.FC<UploadResultsProps> = ({ uploadResults }) => {
22
+ const { errorMessage, failedFiles, filesUploadResult } = uploadResults;
23
+ const [expanded, setExpanded] = useState(false);
24
+
25
+ const countResults = {
26
+ content: { same: 0, updated: 0 },
27
+ images: { same: 0, updated: 0 },
28
+ labels: { same: 0, updated: 0 },
29
+ };
30
+
31
+ filesUploadResult.forEach((result) => {
32
+ countResults.content[result.contentResult]++;
33
+ countResults.images[result.imageResult]++;
34
+ countResults.labels[result.labelResult]++;
35
+ });
36
+
37
+ const renderUpdatedFiles = (type: "content" | "image" | "label") => {
38
+ return filesUploadResult
39
+ .filter((result) => result[`${type}Result`] === "updated")
40
+ .map((result, index) => (
41
+ <li key={index}>
42
+ <a href={result.adfFile.pageUrl}>
43
+ {result.adfFile.absoluteFilePath}
44
+ </a>
45
+ </li>
46
+ ));
47
+ };
48
+
49
+ return (
50
+ <div className="upload-results">
51
+ <div>
52
+ <h1>Confluence Publish</h1>
53
+ </div>
54
+ {errorMessage ? (
55
+ <div className="error-message">
56
+ <h3>Error</h3>
57
+ <p>{errorMessage}</p>
58
+ </div>
59
+ ) : (
60
+ <>
61
+ <div className="successful-uploads">
62
+ <h3>Successful Uploads</h3>
63
+ <p>
64
+ {filesUploadResult.length} file(s) uploaded
65
+ successfully.
66
+ </p>
67
+ </div>
68
+
69
+ {failedFiles.length > 0 && (
70
+ <div className="failed-uploads">
71
+ <h3>Failed Uploads</h3>
72
+ <p>
73
+ {failedFiles.length} file(s) failed to upload.
74
+ </p>
75
+ <ul>
76
+ {failedFiles.map((file, index) => (
77
+ <li key={index}>
78
+ <strong>{file.fileName}</strong>:{" "}
79
+ {file.reason}
80
+ </li>
81
+ ))}
82
+ </ul>
83
+ </div>
84
+ )}
85
+
86
+ <table className="result-table">
87
+ <thead>
88
+ <tr>
89
+ <th>Type</th>
90
+ <th>Same</th>
91
+ <th>Updated</th>
92
+ </tr>
93
+ </thead>
94
+ <tbody>
95
+ <tr>
96
+ <td>Content</td>
97
+ <td>{countResults.content.same}</td>
98
+ <td>{countResults.content.updated}</td>
99
+ </tr>
100
+ <tr>
101
+ <td>Images</td>
102
+ <td>{countResults.images.same}</td>
103
+ <td>{countResults.images.updated}</td>
104
+ </tr>
105
+ <tr>
106
+ <td>Labels</td>
107
+ <td>{countResults.labels.same}</td>
108
+ <td>{countResults.labels.updated}</td>
109
+ </tr>
110
+ </tbody>
111
+ </table>
112
+ <div className="expandable-section">
113
+ <button onClick={() => setExpanded(!expanded)}>
114
+ {expanded ? "Collapse" : "Expand"} Updated Files
115
+ </button>
116
+ {expanded && (
117
+ <div className="updated-files">
118
+ <div className="updated-content">
119
+ <h4>Updated Content</h4>
120
+ <ul>{renderUpdatedFiles("content")}</ul>
121
+ </div>
122
+ <div className="updated-images">
123
+ <h4>Updated Images</h4>
124
+ <ul>{renderUpdatedFiles("image")}</ul>
125
+ </div>
126
+ <div className="updated-labels">
127
+ <h4>Updated Labels</h4>
128
+ <ul>{renderUpdatedFiles("label")}</ul>
129
+ </div>
130
+ </div>
131
+ )}
132
+ </div>
133
+ </>
134
+ )}
135
+ </div>
136
+ );
137
+ };
138
+
139
+ export class CompletedModal extends Modal {
140
+ uploadResults: UploadResultsProps;
141
+
142
+ constructor(app: App, uploadResults: UploadResultsProps) {
143
+ super(app);
144
+ this.uploadResults = uploadResults;
145
+ }
146
+
147
+ override onOpen() {
148
+ const { contentEl } = this;
149
+ ReactDOM.render(
150
+ React.createElement(CompletedView, this.uploadResults),
151
+ contentEl,
152
+ );
153
+ }
154
+
155
+ override onClose() {
156
+ const { contentEl } = this;
157
+ ReactDOM.unmountComponentAtNode(contentEl);
158
+ contentEl.empty();
159
+ }
160
+ }