@valiantys/atlassian-app-frontend 1.0.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.
Files changed (66) hide show
  1. package/README.md +726 -0
  2. package/atlassian-app-forge-CTaVjJLt.js +1 -0
  3. package/atlassian-app-forge-DdtDadi2.mjs +117 -0
  4. package/atlassian-app-frontend.api.json +8829 -0
  5. package/atlassian-app-frontend.api.md +740 -0
  6. package/atlassian-app-standalone-DJOVbfp6.js +1 -0
  7. package/atlassian-app-standalone-DyyH6WPO.mjs +111 -0
  8. package/examples/backend/index.ts +44 -0
  9. package/examples/backend/lib/forge-functions.d.ts +3 -0
  10. package/examples/backend/lib/forge-functions.ts +23 -0
  11. package/examples/backend/lib/handler-functions.d.ts +58 -0
  12. package/examples/backend/lib/handler-functions.ts +72 -0
  13. package/examples/backend/lib/standalone-functions.d.ts +3 -0
  14. package/examples/backend/lib/standalone-functions.ts +17 -0
  15. package/examples/client-sample-.env +5 -0
  16. package/examples/hello-world/app.d.ts +2 -0
  17. package/examples/hello-world/app.tsx +77 -0
  18. package/examples/hello-world/example-box.d.ts +8 -0
  19. package/examples/hello-world/example-box.tsx +22 -0
  20. package/examples/hello-world/example-components/forge-storage-example.d.ts +1 -0
  21. package/examples/hello-world/example-components/forge-storage-example.tsx +66 -0
  22. package/examples/hello-world/example-components/hello-with-loading-spinner.d.ts +1 -0
  23. package/examples/hello-world/example-components/hello-with-loading-spinner.tsx +24 -0
  24. package/examples/hello-world/example-components/hello.d.ts +1 -0
  25. package/examples/hello-world/example-components/hello.spec.tsx +39 -0
  26. package/examples/hello-world/example-components/hello.tsx +13 -0
  27. package/examples/hello-world/example-components/host-router-example.d.ts +1 -0
  28. package/examples/hello-world/example-components/host-router-example.tsx +13 -0
  29. package/examples/hello-world/example-components/issue-types-example-backend.d.ts +4 -0
  30. package/examples/hello-world/example-components/issue-types-example-backend.tsx +37 -0
  31. package/examples/hello-world/example-components/issue-types-example.d.ts +4 -0
  32. package/examples/hello-world/example-components/issue-types-example.tsx +40 -0
  33. package/examples/hello-world/example-components/list-assets.d.ts +1 -0
  34. package/examples/hello-world/example-components/list-assets.tsx +38 -0
  35. package/examples/hello-world/example-components/open-modal-example.d.ts +1 -0
  36. package/examples/hello-world/example-components/open-modal-example.tsx +47 -0
  37. package/examples/hello-world/example-components/view-context-example.d.ts +1 -0
  38. package/examples/hello-world/example-components/view-context-example.tsx +17 -0
  39. package/examples/hello-world/example-components/who-am-i.d.ts +1 -0
  40. package/examples/hello-world/example-components/who-am-i.tsx +13 -0
  41. package/examples/hello-world/main.d.ts +0 -0
  42. package/examples/hello-world/main.tsx +11 -0
  43. package/examples/hello-world/styles.css +1 -0
  44. package/examples/hello-world-modal/app.d.ts +2 -0
  45. package/examples/hello-world-modal/app.tsx +30 -0
  46. package/examples/hello-world-modal/hello.d.ts +1 -0
  47. package/examples/hello-world-modal/hello.tsx +15 -0
  48. package/examples/hello-world-modal/main.d.ts +0 -0
  49. package/examples/hello-world-modal/main.tsx +11 -0
  50. package/examples/hello-world-modal/styles.css +1 -0
  51. package/examples/hello-world-remote/app.d.ts +2 -0
  52. package/examples/hello-world-remote/app.tsx +23 -0
  53. package/examples/hello-world-remote/invoke-remote-example.d.ts +13 -0
  54. package/examples/hello-world-remote/invoke-remote-example.tsx +40 -0
  55. package/examples/hello-world-remote/main.d.ts +0 -0
  56. package/examples/hello-world-remote/main.tsx +11 -0
  57. package/examples/hello-world-remote/styles.css +1 -0
  58. package/examples/manifest.yml.example +49 -0
  59. package/index-CBKhl1FP.mjs +22 -0
  60. package/index-CP8emE0q.js +1 -0
  61. package/index.d.ts +654 -0
  62. package/index.js +2 -0
  63. package/index.mjs +1145 -0
  64. package/package.json +54 -0
  65. package/style.css +1 -0
  66. package/tsdoc-metadata.json +11 -0
@@ -0,0 +1,37 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useBackendAdapter } from '@valiantys/atlassian-app-frontend';
3
+
4
+ /**
5
+ * This component invokes a resolver function on the Forge backend, which then invokes a Jira API.
6
+ */
7
+ export function IssueTypesExampleBackend() {
8
+ const [issueTypes, setIssueTypes] = useState<IssueTypeDetails[]>([]);
9
+ const { invoke } = useBackendAdapter();
10
+
11
+ useEffect(() => {
12
+ invoke<IssueTypeDetails[]>('getIssueTypes').then((types) =>
13
+ setIssueTypes(types)
14
+ );
15
+ }, [invoke]);
16
+
17
+ return (
18
+ <div>
19
+ {issueTypes.map((it) => (
20
+ <div key={it.id}>
21
+ {it.id}: {it.description}
22
+ </div>
23
+ ))}
24
+ </div>
25
+ );
26
+ }
27
+
28
+ interface IssueTypeDetails {
29
+ avatarId: number;
30
+ description: string;
31
+ hierarchyLevel: number;
32
+ iconUrl: string;
33
+ id: string;
34
+ name: string;
35
+ self: string;
36
+ subtask: boolean;
37
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * This component call a Jira API directly from the client using requestJira.
3
+ */
4
+ export declare function IssueTypesExample(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,40 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useRequestJira } from '@valiantys/atlassian-app-frontend';
3
+
4
+ /**
5
+ * This component call a Jira API directly from the client using requestJira.
6
+ */
7
+ export function IssueTypesExample() {
8
+ const [issueTypes, setIssueTypes] = useState<IssueTypeDetails[]>([]);
9
+ const requestJiraSvc = useRequestJira();
10
+
11
+ useEffect(() => {
12
+ requestJiraSvc
13
+ .fetch<IssueTypeDetails[]>({
14
+ url: requestJiraSvc.route`/rest/api/2/issuetype`,
15
+ method: 'GET',
16
+ })
17
+ .then((types) => setIssueTypes(types));
18
+ }, [requestJiraSvc]);
19
+
20
+ return (
21
+ <div>
22
+ {issueTypes.map((it) => (
23
+ <div key={it.id}>
24
+ {it.id}: {it.description}
25
+ </div>
26
+ ))}
27
+ </div>
28
+ );
29
+ }
30
+
31
+ interface IssueTypeDetails {
32
+ avatarId: number;
33
+ description: string;
34
+ hierarchyLevel: number;
35
+ iconUrl: string;
36
+ id: string;
37
+ name: string;
38
+ self: string;
39
+ subtask: boolean;
40
+ }
@@ -0,0 +1 @@
1
+ export declare function ListAssets(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { useCallback } from 'react';
2
+ import {
3
+ PageLoadingView,
4
+ useLoadDataEffect,
5
+ useRequestJira,
6
+ useWorkspaceId,
7
+ } from '@valiantys/atlassian-app-frontend';
8
+
9
+ interface AssetSchema {
10
+ name: string;
11
+ id: string;
12
+ }
13
+
14
+ export function ListAssets() {
15
+ const jiraFetchService = useRequestJira();
16
+ const workspaceId = useWorkspaceId();
17
+
18
+ const listAssetsSchemas = useCallback(async () => {
19
+ if (jiraFetchService && workspaceId) {
20
+ const paginatedResult = await jiraFetchService.fetch<{
21
+ values: AssetSchema[];
22
+ }>({
23
+ url: jiraFetchService.route`/jsm/assets/workspace/${workspaceId}/v1/objectschema/list`,
24
+ method: 'GET',
25
+ });
26
+ return paginatedResult.values;
27
+ }
28
+ return [];
29
+ }, [jiraFetchService, workspaceId]);
30
+
31
+ const { data, loading, error } =
32
+ useLoadDataEffect<AssetSchema[]>(listAssetsSchemas);
33
+ return loading || error ? (
34
+ <PageLoadingView label="" loadingError={error} />
35
+ ) : (
36
+ <div>{data?.map((schema) => <div key={schema.id}>{schema.name}</div>)}</div>
37
+ );
38
+ }
@@ -0,0 +1 @@
1
+ export declare function OpenModalExample(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,47 @@
1
+ import Button from '@atlaskit/button/new';
2
+ import Textfield from '@atlaskit/textfield';
3
+
4
+ import { useModalService } from '@valiantys/atlassian-app-frontend';
5
+ import { useCallback, useState } from 'react';
6
+
7
+ export function OpenModalExample() {
8
+ const [isOpen, setIsOpen] = useState<boolean>(false);
9
+ const [text, setText] = useState<string>('Hello');
10
+
11
+ const modalService = useModalService();
12
+
13
+ const openModal = useCallback(() => {
14
+ if (!isOpen) {
15
+ setIsOpen(true);
16
+ void modalService.open({
17
+ resource: 'hello-world-modal', // must be the key of a resource defined in manifest.yml
18
+ onClose: () => {
19
+ setIsOpen(false);
20
+ },
21
+ /*
22
+ small - w: 400px h: 20vh minHeight: 320px
23
+ medium - w: 600px h: 40vh minHeight: 520px
24
+ large - w: 800px h: 70vh minHeight: 720px
25
+ xlarge - w: 968px h: 90vh
26
+ max - w: 100% h: 100%
27
+ */
28
+ size: 'large',
29
+ context: {
30
+ text,
31
+ },
32
+ closeOnEscape: true,
33
+ closeOnOverlayClick: true,
34
+ });
35
+ }
36
+ }, [modalService, isOpen, text]);
37
+
38
+ return (
39
+ <div>
40
+ <Textfield
41
+ value={text}
42
+ onChange={(e) => setText((e.target as HTMLInputElement).value)}
43
+ ></Textfield>
44
+ <Button onClick={openModal}>Open Modal</Button>
45
+ </div>
46
+ );
47
+ }
@@ -0,0 +1 @@
1
+ export declare function ViewContextExample(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { useViewContext } from '@valiantys/atlassian-app-frontend';
2
+ import { useEffect, useState } from 'react';
3
+
4
+ export function ViewContextExample() {
5
+ const viewContext = useViewContext();
6
+ const [contextData, setContextData] = useState<string | undefined>();
7
+
8
+ useEffect(() => {
9
+ if (viewContext) {
10
+ viewContext
11
+ .getContext()
12
+ .then((fullContext) => setContextData(JSON.stringify(fullContext)));
13
+ }
14
+ }, [viewContext]);
15
+
16
+ return <div>{contextData}</div>;
17
+ }
@@ -0,0 +1 @@
1
+ export declare function WhoAmI(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useBackendAdapter } from '@valiantys/atlassian-app-frontend';
3
+
4
+ export function WhoAmI() {
5
+ const [id, setId] = useState<string>('');
6
+ const { invoke } = useBackendAdapter();
7
+
8
+ useEffect(() => {
9
+ invoke<{ myId: string }>('whoAmI').then((response) => setId(response.myId));
10
+ }, [invoke]);
11
+
12
+ return <div>My Atlassian ID is {id}</div>;
13
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import * as ReactDOM from 'react-dom/client';
2
+
3
+ import App from './app';
4
+
5
+ import '@atlaskit/css-reset';
6
+
7
+ const root = ReactDOM.createRoot(
8
+ document.getElementById('root') as HTMLElement
9
+ );
10
+
11
+ root.render(<App />);
@@ -0,0 +1 @@
1
+ @import '../node_modules/@valiantys/atlassian-app-frontend/style.css';
@@ -0,0 +1,2 @@
1
+ declare function App(): import('react/jsx-runtime').JSX.Element;
2
+ export default App;
@@ -0,0 +1,30 @@
1
+ import { AtlassianApp, ModalContent } from '@valiantys/atlassian-app-frontend';
2
+ import { Hello } from './hello';
3
+
4
+ function App() {
5
+ return (
6
+ <AtlassianApp
7
+ appName="hello-modal"
8
+ standaloneConfig={{
9
+ modalContextConfig: { openerOrigin: 'http://localhost:4200' },
10
+ initialMockViewContext: {
11
+ extension: {
12
+ // This is a hard-coded version of the data that will be passed
13
+ // from the opening app when running in an Atlassian environment.
14
+ modal: {
15
+ text: 'Hello Bob',
16
+ },
17
+ },
18
+ },
19
+ }}
20
+ embeddedConfig={{}}
21
+ >
22
+ {/* ModalContent component provides modal-related services, see Hello component for example usage. */}
23
+ <ModalContent>
24
+ <Hello></Hello>
25
+ </ModalContent>
26
+ </AtlassianApp>
27
+ );
28
+ }
29
+
30
+ export default App;
@@ -0,0 +1 @@
1
+ export declare function Hello(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,15 @@
1
+ import Button from '@atlaskit/button/new';
2
+ import { useModalContentService } from '@valiantys/atlassian-app-frontend';
3
+
4
+ export function Hello() {
5
+ const { modalContextData, close } = useModalContentService<{
6
+ text: string;
7
+ }>();
8
+
9
+ return (
10
+ <div>
11
+ <div>{modalContextData?.text}</div>
12
+ <Button onClick={close}>Close Modal</Button>
13
+ </div>
14
+ );
15
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import * as ReactDOM from 'react-dom/client';
2
+
3
+ import App from './app';
4
+
5
+ import '@atlaskit/css-reset';
6
+
7
+ const root = ReactDOM.createRoot(
8
+ document.getElementById('root') as HTMLElement
9
+ );
10
+
11
+ root.render(<App />);
@@ -0,0 +1 @@
1
+ @import '../node_modules/@valiantys/atlassian-app-frontend/style.css';
@@ -0,0 +1,2 @@
1
+ declare function App(): import('react/jsx-runtime').JSX.Element;
2
+ export default App;
@@ -0,0 +1,23 @@
1
+ import Heading from '@atlaskit/heading';
2
+ import { Box } from '@atlaskit/primitives';
3
+ import { AtlassianApp } from '@valiantys/atlassian-app-frontend';
4
+ import { InvokeRemoteExample } from './invoke-remote-example';
5
+
6
+ function App() {
7
+ return (
8
+ <AtlassianApp
9
+ appName="hello-remote"
10
+ standaloneConfig={{
11
+ remoteUrl: 'https://jsonplaceholder.typicode.com/', // For invokeRemote from client (useRemoteAdapter)
12
+ }}
13
+ embeddedConfig={{}}
14
+ >
15
+ <Box paddingBlockEnd="space.200">
16
+ <Heading size="small">useRemoteAdapter Example (invokeRemote)</Heading>
17
+ <InvokeRemoteExample></InvokeRemoteExample>
18
+ </Box>
19
+ </AtlassianApp>
20
+ );
21
+ }
22
+
23
+ export default App;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * manifest.yml must contain this configuration to enable the remote invocation:
3
+ *
4
+ * remotes:
5
+ * - key: example-remote
6
+ * baseUrl: https://jsonplaceholder.typicode.com
7
+ * permissions:
8
+ * external:
9
+ * fetch:
10
+ * client:
11
+ * - remote: example-remote
12
+ */
13
+ export declare function InvokeRemoteExample(): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * manifest.yml must contain this configuration to enable the remote invocation:
3
+ *
4
+ * remotes:
5
+ * - key: example-remote
6
+ * baseUrl: https://jsonplaceholder.typicode.com
7
+ * permissions:
8
+ * external:
9
+ * fetch:
10
+ * client:
11
+ * - remote: example-remote
12
+ */
13
+
14
+ import { useRemoteAdapter } from '@valiantys/atlassian-app-frontend';
15
+ import { useEffect, useState } from 'react';
16
+
17
+ interface Todo {
18
+ completed: boolean;
19
+ id: number;
20
+ title: string;
21
+ userId: number;
22
+ }
23
+
24
+ export function InvokeRemoteExample() {
25
+ const remoteSvc = useRemoteAdapter();
26
+ const [todo, setTodo] = useState<Todo | undefined>(undefined);
27
+
28
+ useEffect(() => {
29
+ remoteSvc
30
+ .invokeRemote<Todo, void>({
31
+ path: '/todos/1',
32
+ method: 'GET',
33
+ headers: { accept: 'application/json' },
34
+ })
35
+ .then((response) => setTodo(response.body))
36
+ .catch((error) => console.error('remote error', error));
37
+ }, [remoteSvc]);
38
+
39
+ return <div>Todo: {todo?.title}</div>;
40
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import * as ReactDOM from 'react-dom/client';
2
+
3
+ import App from './app';
4
+
5
+ import '@atlaskit/css-reset';
6
+
7
+ const root = ReactDOM.createRoot(
8
+ document.getElementById('root') as HTMLElement
9
+ );
10
+
11
+ root.render(<App />);
@@ -0,0 +1 @@
1
+ @import '../node_modules/@valiantys/atlassian-app-frontend/style.css';
@@ -0,0 +1,49 @@
1
+ modules:
2
+ jira:globalPage:
3
+ - key: hello-world-page
4
+ resource: hello-world-resource
5
+ resolver:
6
+ function: resolver
7
+ title: Hello world
8
+ jira:issuePanel:
9
+ - key: hello-world-remote-example
10
+ resource: hello-remote-resource
11
+ resolver:
12
+ endpoint: example-remote-endpoint
13
+ title: Hello world Remote
14
+ icon: https://developer.atlassian.com/platform/forge/images/icons/issue-panel-icon.svg
15
+ function:
16
+ - key: resolver
17
+ handler: index.handler
18
+ endpoint: # for using invokeRemote to access external API from client (must be internet accessible)
19
+ - key: example-remote-endpoint
20
+ remote: example-remote
21
+ remotes:
22
+ - key: example-remote
23
+ baseUrl: https://jsonplaceholder.typicode.com
24
+
25
+ resources:
26
+ - key: hello-world-resource
27
+ path: static/hello-world/dist
28
+ - key: hello-remote-resource
29
+ path: static/hello-world-remote/dist
30
+ - key: hello-world-modal
31
+ path: static/hello-world-modal/dist
32
+ permissions:
33
+ external:
34
+ fetch:
35
+ client:
36
+ - remote: example-remote
37
+ content:
38
+ styles:
39
+ - 'unsafe-inline'
40
+ scopes:
41
+ - read:jira-user
42
+ - read:jira-work
43
+ - read:servicedesk-request
44
+ - read:cmdb-schema:jira
45
+ - storage:app
46
+ app:
47
+ runtime:
48
+ name: nodejs20.x
49
+ id: ari:cloud:ecosystem::app/<app-id>
@@ -0,0 +1,22 @@
1
+ import { FeatureChosenResourceCheck as r } from "./index.mjs";
2
+ import "react/jsx-runtime";
3
+ import "@atlaskit/button";
4
+ import "@atlaskit/button/new";
5
+ import "@atlaskit/form";
6
+ import "@atlaskit/primitives";
7
+ import "@atlaskit/section-message";
8
+ import "@atlaskit/select";
9
+ import "react";
10
+ import "@atlaskit/heading";
11
+ import "@atlaskit/spinner";
12
+ import "react-router-dom";
13
+ import "@atlaskit/flag";
14
+ import "@atlaskit/icon/glyph/check-circle";
15
+ import "@atlaskit/icon/glyph/error";
16
+ import "@atlaskit/icon/glyph/info";
17
+ import "@atlaskit/icon/glyph/warning";
18
+ import "@atlaskit/tokens";
19
+ export {
20
+ r as FeatureChosenResourceCheck,
21
+ r as default
22
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index.js");require("react/jsx-runtime");require("@atlaskit/button");require("@atlaskit/button/new");require("@atlaskit/form");require("@atlaskit/primitives");require("@atlaskit/section-message");require("@atlaskit/select");require("react");require("@atlaskit/heading");require("@atlaskit/spinner");require("react-router-dom");require("@atlaskit/flag");require("@atlaskit/icon/glyph/check-circle");require("@atlaskit/icon/glyph/error");require("@atlaskit/icon/glyph/info");require("@atlaskit/icon/glyph/warning");require("@atlaskit/tokens");exports.FeatureChosenResourceCheck=e.FeatureChosenResourceCheck;exports.default=e.FeatureChosenResourceCheck;