Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cortex Scaffolder] Creating new service: confluence-plugin #22

Closed
wants to merge 1 commit into from
Closed
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 plugins/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
30 changes: 30 additions & 0 deletions plugins/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"standard-with-typescript",
"prettier",
],
overrides: [],
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.json",
sourceType: "module",
tsconfigRootDir: __dirname,
},
plugins: ["react"],
rules: {
// conflicts with no-extra-boolean-cast
"@typescript-eslint/strict-boolean-expressions": "off",
"no-console": ["error", { allow: ["warn", "error"] }],
},
settings: {
react: {
version: "detect",
},
},
};
12 changes: 12 additions & 0 deletions plugins/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# OSX
*.DS_Store

# IDEs
.idea
*.iml
.vscode

# This project
node_modules/
dist/
yarn-error.log
2 changes: 2 additions & 0 deletions plugins/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
28 changes: 28 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# confluence-plugin

confluence-plugin is a [Cortex](https://www.cortex.io/) plugin. To see how to run the plugin inside of Cortex, see [our docs](https://docs.cortex.io/docs/plugins).

### Prerequisites

Developing and building this plugin requires either [yarn](https://classic.yarnpkg.com/lang/en/docs/install/) or [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

## Getting started

1. Run `yarn` or `npm install` to download all dependencies
2. Run `yarn build` or `npm run build` to compile the plugin code into `./dist/ui.html`
3. Upload `ui.html` into Cortex on a create or edit plugin page
4. Add or update the code and repeat steps 2-3 as necessary

### Notable scripts

The following commands come pre-configured in this repository. You can see all available commands in the `scripts` section of [package.json](./package.json). They can be run with npm via `npm run {script_name}` or with yarn via `yarn {script_name}`, depending on your package manager preference. For instance, the `build` command can be run with `npm run build` or `yarn build`.

- `build` - compiles the plugin. The compiled code root is `./src/index.tsx` (or as defined by [webpack.config.js](webpack.config.js)) and the output is generated into `dist/ui.html`.
- `test` - runs all tests defined in the repository using [jest](https://jestjs.io/)
- `lint` - runs lint and format checking on the repository using [prettier](https://prettier.io/) and [eslint](https://eslint.org/)
- `lintfix` - runs eslint in fix mode to fix any linting errors that can be fixed automatically
- `formatfix` - runs Prettier in fix mode to fix any formatting errors that can be fixed automatically

### Available React components

See available UI components via our [Storybook](https://cortexapps.github.io/plugin-core/).
1 change: 1 addition & 0 deletions plugins/__mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = "test-file-stub";
1 change: 1 addition & 0 deletions plugins/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
8 changes: 8 additions & 0 deletions plugins/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
plugins: ["@babel/plugin-syntax-jsx"],
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
["@babel/preset-react", { runtime: "automatic" }],
],
};
12 changes: 12 additions & 0 deletions plugins/cortex.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
openapi: 3.0.1
info:
title: confluence-plugin
description: ""
x-cortex-tag: confluence-plugin
x-cortex-git:
github:
repository: cortexapps/cortex-plugins
basepath: plugins
x-cortex-custom-metadata:
cortex-template-version: 0.1.0
cortex-generated-timestamp: 2024-01-25T14:40:03.811553442
18 changes: 18 additions & 0 deletions plugins/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
moduleNameMapper: {
// map static asset imports to a stub file under the assumption they are not important to our tests
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/__mocks__/fileMock.js",
// map style asset imports to a stub file under the assumption they are not important to our tests
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
"@cortexapps/plugin-core/components":
"<rootDir>/node_modules/@cortexapps/plugin-core/dist/components.cjs.js",
"@cortexapps/plugin-core":
"<rootDir>/node_modules/@cortexapps/plugin-core/dist/index.cjs.js",
},
setupFilesAfterEnv: ["<rootDir>/setupTests.ts"],
testEnvironment: "jsdom",
transform: {
"^.+\\.tsx?$": "babel-jest",
},
};
61 changes: 61 additions & 0 deletions plugins/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "confluence-plugin",
"version": "0.1.0",
"license": "MIT",
"dependencies": {
"@cortexapps/plugin-core": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/core": "^7.21.3",
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@popperjs/core": "^2.11.8",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.55.0",
"babel-jest": "^29.5.0",
"css-loader": "^6.7.3",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.7.0",
"eslint-config-standard-with-typescript": "^34.0.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"html-webpack-plugin": "^5.5.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.4",
"prop-types": "^15.8.1",
"react-dev-utils": "^12.0.1",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.7",
"ts-loader": "^9.4.2",
"typescript": "^4.9.5",
"url-loader": "^4.1.1",
"webpack": "^5.76.1",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.15.0"
},
"scripts": {
"build": "webpack --mode=production",
"clean": "rm -r ./dist",
"dev": "webpack serve --mode=development",
"fix": "run-p formatfix lintfix",
"formatfix": "yarn prettier . --write",
"formatcheck": "yarn prettier . --check",
"lint": "run-p formatcheck lintcheck",
"lintcheck": "yarn eslint src",
"lintfix": "yarn lintcheck --fix",
"test": "jest"
}
}
57 changes: 57 additions & 0 deletions plugins/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import "@testing-library/jest-dom/extend-expect";

const mockContext = {
apiBaseUrl: "https://api.cortex.dev",
entity: {
definition: null,
description: null,
groups: null,
name: "Inventory planner",
ownership: {
emails: [
{
description: null,
email: "[email protected]",
inheritance: null,
id: 1,
},
],
},
tag: "inventory-planner",
type: "service",
},
location: "ENTITY",
user: {
email: "[email protected]",
name: "Ganesh Datta",
role: "ADMIN",
},
};

jest.mock("@cortexapps/plugin-core/components", () => {
const originalModule = jest.requireActual(
"@cortexapps/plugin-core/components"
);
return {
...originalModule,
usePluginContext: () => {
return mockContext;
},
PluginProvider: ({ children }) => {
return children;
},
};
});

jest.mock("@cortexapps/plugin-core", () => {
const originalModule = jest.requireActual("@cortexapps/plugin-core");
return {
...originalModule,
CortexApi: {
...originalModule.CortexApi,
getContext: () => {
return mockContext;
},
},
};
});
7 changes: 7 additions & 0 deletions plugins/src/api/Cortex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CortexApi, type CortexContextResponse } from "@cortexapps/plugin-core";

export const getCortexContext = async (): Promise<CortexContextResponse> => {
const context = await CortexApi.getContext();

return context;
};
3 changes: 3 additions & 0 deletions plugins/src/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions plugins/src/baseStyles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
font: 14px sans-serif;
}
10 changes: 10 additions & 0 deletions plugins/src/components/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render, screen } from "@testing-library/react";
import App from "./App";

describe("App", () => {
it("indicates that it's an awesome plugin", () => {
render(<App />);

expect(screen.queryByText(/My Awesome Cortex Plugin/)).toBeInTheDocument();
});
});
26 changes: 26 additions & 0 deletions plugins/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type React from "react";
import {
Logo,
PluginProvider,
Stack,
Title,
} from "@cortexapps/plugin-core/components";
import "../baseStyles.css";
import ErrorBoundary from "./ErrorBoundary";
import PluginContext from "./PluginContext";

const App: React.FC = () => {
return (
<ErrorBoundary>
<PluginProvider>
<Stack>
<Logo />
<Title level={1}>My Awesome Cortex Plugin</Title>
</Stack>
<PluginContext />
</PluginProvider>
</ErrorBoundary>
);
};

export default App;
39 changes: 39 additions & 0 deletions plugins/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";

interface ErrorBoundaryProps extends React.PropsWithChildren {}

interface ErrorBoundaryState {
hasError: boolean;
}

class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
public state: ErrorBoundaryState = {
hasError: false,
};

public static getDerivedStateFromError(_: Error): ErrorBoundaryState {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

public componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
console.error("Uncaught error:", error, errorInfo);
}

public render(): React.ReactNode {
if (this.state.hasError) {
return (
<h1>
Oops! There was a runtime error. See the console for more details.
</h1>
);
}

return this.props.children;
}
}

export default ErrorBoundary;
15 changes: 15 additions & 0 deletions plugins/src/components/PluginContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Title, usePluginContext } from "@cortexapps/plugin-core/components";
import type React from "react";

const PluginContext: React.FC = () => {
const context = usePluginContext();

return (
<>
<Title level={2}>Plugin context</Title>
<pre>{JSON.stringify(context, null, 2)}</pre>
</>
);
};

export default PluginContext;
10 changes: 10 additions & 0 deletions plugins/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html>
<head>
<script
defer
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.7/iframeResizer.contentWindow.js"
></script>
</head>
<div id="cortex-plugin-root"></div>
</html>
9 changes: 9 additions & 0 deletions plugins/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createRoot } from "react-dom/client";
import App from "./components/App";

document.addEventListener("DOMContentLoaded", function () {
const container = document.getElementById("cortex-plugin-root");
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const root = createRoot(container!);
root.render(<App />);
});
4 changes: 4 additions & 0 deletions plugins/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module "*.svg" {
const content: any;
export default content;
}
16 changes: 16 additions & 0 deletions plugins/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "dist",
"removeComments": true,
"strictNullChecks": true,
"target": "es6",
"typeRoots": ["./node_modules/@types"]
}
}
Loading
Loading