@dxos/plugin-github 0.6.8-main.046e6cf
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/LICENSE +8 -0
- package/README.md +15 -0
- package/dist/lib/browser/chunk-NJP5BGD2.mjs +24 -0
- package/dist/lib/browser/chunk-NJP5BGD2.mjs.map +7 -0
- package/dist/lib/browser/index.css +7 -0
- package/dist/lib/browser/index.css.map +7 -0
- package/dist/lib/browser/index.mjs +1531 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/browser/meta.mjs +11 -0
- package/dist/lib/browser/meta.mjs.map +7 -0
- package/dist/types/src/GithubPlugin.d.ts +4 -0
- package/dist/types/src/GithubPlugin.d.ts.map +1 -0
- package/dist/types/src/components/EmbeddedMain/EmbeddedMain.d.ts +4 -0
- package/dist/types/src/components/EmbeddedMain/EmbeddedMain.d.ts.map +1 -0
- package/dist/types/src/components/EmbeddedMain/GfmPreview.d.ts +9 -0
- package/dist/types/src/components/EmbeddedMain/GfmPreview.d.ts.map +1 -0
- package/dist/types/src/components/EmbeddedMain/index.d.ts +2 -0
- package/dist/types/src/components/EmbeddedMain/index.d.ts.map +1 -0
- package/dist/types/src/components/ExportDialog.d.ts +8 -0
- package/dist/types/src/components/ExportDialog.d.ts.map +1 -0
- package/dist/types/src/components/GithubApiProviders/GitHubSettings.d.ts +3 -0
- package/dist/types/src/components/GithubApiProviders/GitHubSettings.d.ts.map +1 -0
- package/dist/types/src/components/GithubApiProviders/OctokitProvider.d.ts +15 -0
- package/dist/types/src/components/GithubApiProviders/OctokitProvider.d.ts.map +1 -0
- package/dist/types/src/components/GithubApiProviders/index.d.ts +3 -0
- package/dist/types/src/components/GithubApiProviders/index.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/DocumentTreeItem.d.ts +6 -0
- package/dist/types/src/components/GithubEchoResolverProviders/DocumentTreeItem.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverContext.d.ts +7 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverContext.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverDialog.d.ts +6 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverDialog.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverProps.d.ts +16 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverProps.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverTree.d.ts +3 -0
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverTree.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.d.ts +11 -0
- package/dist/types/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/index.d.ts +3 -0
- package/dist/types/src/components/GithubEchoResolverProviders/index.d.ts.map +1 -0
- package/dist/types/src/components/GithubEchoResolverProviders/spaceResolvers.d.ts +6 -0
- package/dist/types/src/components/GithubEchoResolverProviders/spaceResolvers.d.ts.map +1 -0
- package/dist/types/src/components/ImportDialog.d.ts +7 -0
- package/dist/types/src/components/ImportDialog.d.ts.map +1 -0
- package/dist/types/src/components/Issue.d.ts +5 -0
- package/dist/types/src/components/Issue.d.ts.map +1 -0
- package/dist/types/src/components/Loading/Loading.d.ts +15 -0
- package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
- package/dist/types/src/components/Loading/Loading.stories.d.ts +52 -0
- package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
- package/dist/types/src/components/Loading/index.d.ts +2 -0
- package/dist/types/src/components/Loading/index.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownActions.d.ts +7 -0
- package/dist/types/src/components/MarkdownActions.d.ts.map +1 -0
- package/dist/types/src/components/UrlDialog.d.ts +6 -0
- package/dist/types/src/components/UrlDialog.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +9 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +3 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useDocGhId.d.ts +6 -0
- package/dist/types/src/hooks/useDocGhId.d.ts.map +1 -0
- package/dist/types/src/hooks/useGhIdFromUrl.d.ts +2 -0
- package/dist/types/src/hooks/useGhIdFromUrl.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +16 -0
- package/dist/types/src/meta.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +56 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +30 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/package.json +76 -0
- package/src/GithubPlugin.tsx +129 -0
- package/src/components/EmbeddedMain/EmbeddedMain.tsx +296 -0
- package/src/components/EmbeddedMain/GfmPreview.tsx +110 -0
- package/src/components/EmbeddedMain/embedded.css +3 -0
- package/src/components/EmbeddedMain/index.ts +5 -0
- package/src/components/ExportDialog.tsx +157 -0
- package/src/components/GithubApiProviders/GitHubSettings.tsx +72 -0
- package/src/components/GithubApiProviders/OctokitProvider.tsx +60 -0
- package/src/components/GithubApiProviders/index.ts +6 -0
- package/src/components/GithubEchoResolverProviders/DocumentTreeItem.tsx +26 -0
- package/src/components/GithubEchoResolverProviders/ResolverContext.tsx +140 -0
- package/src/components/GithubEchoResolverProviders/ResolverDialog.tsx +34 -0
- package/src/components/GithubEchoResolverProviders/ResolverProps.ts +23 -0
- package/src/components/GithubEchoResolverProviders/ResolverTree.tsx +86 -0
- package/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.tsx +105 -0
- package/src/components/GithubEchoResolverProviders/index.ts +6 -0
- package/src/components/GithubEchoResolverProviders/spaceResolvers.ts +86 -0
- package/src/components/ImportDialog.tsx +72 -0
- package/src/components/Issue.tsx +62 -0
- package/src/components/Loading/Loading.stories.tsx +28 -0
- package/src/components/Loading/Loading.tsx +70 -0
- package/src/components/Loading/index.ts +5 -0
- package/src/components/MarkdownActions.tsx +136 -0
- package/src/components/UrlDialog.tsx +52 -0
- package/src/components/index.ts +12 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useDocGhId.ts +38 -0
- package/src/hooks/useGhIdFromUrl.ts +26 -0
- package/src/index.ts +9 -0
- package/src/meta.tsx +21 -0
- package/src/translations.ts +72 -0
- package/src/types.ts +51 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import './embedded.css';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ArrowSquareOut,
|
|
9
|
+
CaretDown,
|
|
10
|
+
DotsThreeVertical,
|
|
11
|
+
Eye,
|
|
12
|
+
Option,
|
|
13
|
+
PencilSimpleLine,
|
|
14
|
+
UserPlus,
|
|
15
|
+
} from '@phosphor-icons/react';
|
|
16
|
+
import React, { useCallback, useContext, useRef, useState } from 'react';
|
|
17
|
+
|
|
18
|
+
import { Surface, useIntent } from '@dxos/app-framework';
|
|
19
|
+
import { SPACE_PLUGIN, SpaceAction, getSpaceDisplayName } from '@dxos/plugin-space';
|
|
20
|
+
import { useClient } from '@dxos/react-client';
|
|
21
|
+
import { getMeta } from '@dxos/react-client/echo';
|
|
22
|
+
import {
|
|
23
|
+
Avatar,
|
|
24
|
+
Button,
|
|
25
|
+
ButtonGroup,
|
|
26
|
+
DensityProvider,
|
|
27
|
+
Dialog,
|
|
28
|
+
DropdownMenu,
|
|
29
|
+
Main,
|
|
30
|
+
Toggle,
|
|
31
|
+
Tooltip,
|
|
32
|
+
toLocalizedString,
|
|
33
|
+
useTranslation,
|
|
34
|
+
} from '@dxos/react-ui';
|
|
35
|
+
import { defaultTx, descriptionText, getSize, mx } from '@dxos/react-ui-theme';
|
|
36
|
+
import { hexToFallback } from '@dxos/util';
|
|
37
|
+
|
|
38
|
+
import { GfmPreview } from './GfmPreview';
|
|
39
|
+
import { useDocGhId } from '../../hooks';
|
|
40
|
+
import { GITHUB_PLUGIN } from '../../meta';
|
|
41
|
+
import type { EditorViewState } from '../../types';
|
|
42
|
+
import {
|
|
43
|
+
DocumentResolverProvider,
|
|
44
|
+
DocumentResolverContext,
|
|
45
|
+
ResolverDialog,
|
|
46
|
+
SpaceResolverProvider,
|
|
47
|
+
SpaceResolverContext,
|
|
48
|
+
} from '../GithubEchoResolverProviders';
|
|
49
|
+
|
|
50
|
+
const overlayAttrs = { side: 'top' as const, sideOffset: 4 };
|
|
51
|
+
|
|
52
|
+
const EmbeddedLayoutImpl = () => {
|
|
53
|
+
const { t } = useTranslation(GITHUB_PLUGIN);
|
|
54
|
+
const { space, source, id, identityHex } = useContext(SpaceResolverContext);
|
|
55
|
+
const { document } = useContext(DocumentResolverContext);
|
|
56
|
+
const { dispatch } = useIntent();
|
|
57
|
+
const client = useClient();
|
|
58
|
+
|
|
59
|
+
const handleCloseEmbed = useCallback(() => {
|
|
60
|
+
window.parent.postMessage({ type: 'close-embed' }, 'https://github.com');
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const handleSaveAndCloseEmbed = useCallback(() => {
|
|
64
|
+
document &&
|
|
65
|
+
window.parent.postMessage({ type: 'save-data', content: document.content?.content }, 'https://github.com');
|
|
66
|
+
}, [document]);
|
|
67
|
+
|
|
68
|
+
const handleCreateSpace = () => dispatch({ action: SpaceAction.CREATE });
|
|
69
|
+
const handleJoinSpace = () => dispatch({ action: SpaceAction.JOIN });
|
|
70
|
+
|
|
71
|
+
const handleInvite = useCallback(() => {
|
|
72
|
+
if (client && space) {
|
|
73
|
+
void client.shell.shareSpace({ spaceKey: space.key });
|
|
74
|
+
}
|
|
75
|
+
}, [client, space]);
|
|
76
|
+
|
|
77
|
+
const [editorViewState, setEditorViewState] = useState<EditorViewState>('editor');
|
|
78
|
+
const isPreviewing = editorViewState === 'preview';
|
|
79
|
+
|
|
80
|
+
const suppressNextTooltip = useRef<boolean>(false);
|
|
81
|
+
const [optionsTooltipOpen, setOptionsTooltipOpen] = useState(false);
|
|
82
|
+
const [optionsMenuOpen, setOptionsMenuOpen] = useState(false);
|
|
83
|
+
|
|
84
|
+
const [renameDialogOpen, setRenameDialogOpen] = useState(false);
|
|
85
|
+
const [resolverDialogOpen, setResolverDialogOpen] = useState(false);
|
|
86
|
+
|
|
87
|
+
const spaceFallbackValue = hexToFallback(space?.key.toHex() ?? '0');
|
|
88
|
+
|
|
89
|
+
const docGhId = useDocGhId((document ? getMeta(document)?.keys : []) ?? []);
|
|
90
|
+
const name = space && getSpaceDisplayName(space);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<style type='text/css'>{`
|
|
95
|
+
:root {
|
|
96
|
+
--surface-bg: #F6F8FA;
|
|
97
|
+
}
|
|
98
|
+
.dark:root {
|
|
99
|
+
--surface-bg: #161b22;
|
|
100
|
+
}
|
|
101
|
+
`}</style>
|
|
102
|
+
<DensityProvider density='fine'>
|
|
103
|
+
<div role='none' className='fixed inline-end-2 block-end-2 z-10 flex gap-2'>
|
|
104
|
+
<Tooltip.Root>
|
|
105
|
+
<Tooltip.Trigger asChild>
|
|
106
|
+
<Button disabled={!space} onClick={handleInvite}>
|
|
107
|
+
<span className='sr-only'>{t('create invitation label', { ns: 'appkit' })}</span>
|
|
108
|
+
<UserPlus className={getSize(5)} />
|
|
109
|
+
</Button>
|
|
110
|
+
</Tooltip.Trigger>
|
|
111
|
+
<Tooltip.Content {...overlayAttrs}>
|
|
112
|
+
{t('create invitation label', { ns: 'appkit' })}
|
|
113
|
+
<Tooltip.Arrow />
|
|
114
|
+
</Tooltip.Content>
|
|
115
|
+
</Tooltip.Root>
|
|
116
|
+
<Tooltip.Root>
|
|
117
|
+
<Tooltip.Trigger asChild>
|
|
118
|
+
<Toggle
|
|
119
|
+
disabled={!(space && document)}
|
|
120
|
+
pressed={isPreviewing}
|
|
121
|
+
onPressedChange={(nextPressed) => setEditorViewState(nextPressed ? 'preview' : 'editor')}
|
|
122
|
+
>
|
|
123
|
+
<span className='sr-only'>{t(isPreviewing ? 'exit gfm preview label' : 'preview gfm label')}</span>
|
|
124
|
+
{isPreviewing ? <PencilSimpleLine className={getSize(5)} /> : <Eye className={getSize(5)} />}
|
|
125
|
+
</Toggle>
|
|
126
|
+
</Tooltip.Trigger>
|
|
127
|
+
<Tooltip.Content {...overlayAttrs}>
|
|
128
|
+
{t(isPreviewing ? 'exit gfm preview label' : 'preview gfm label')}
|
|
129
|
+
<Tooltip.Arrow />
|
|
130
|
+
</Tooltip.Content>
|
|
131
|
+
</Tooltip.Root>
|
|
132
|
+
<Tooltip.Root
|
|
133
|
+
open={optionsTooltipOpen}
|
|
134
|
+
onOpenChange={(nextOpen) => {
|
|
135
|
+
if (suppressNextTooltip.current) {
|
|
136
|
+
setOptionsTooltipOpen(false);
|
|
137
|
+
suppressNextTooltip.current = false;
|
|
138
|
+
} else {
|
|
139
|
+
setOptionsTooltipOpen(nextOpen);
|
|
140
|
+
}
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
<DropdownMenu.Root
|
|
144
|
+
{...{
|
|
145
|
+
modal: false,
|
|
146
|
+
open: optionsMenuOpen,
|
|
147
|
+
onOpenChange: (nextOpen: boolean) => {
|
|
148
|
+
if (!nextOpen) {
|
|
149
|
+
suppressNextTooltip.current = true;
|
|
150
|
+
}
|
|
151
|
+
return setOptionsMenuOpen(nextOpen);
|
|
152
|
+
},
|
|
153
|
+
}}
|
|
154
|
+
>
|
|
155
|
+
<Tooltip.Trigger asChild>
|
|
156
|
+
<DropdownMenu.Trigger asChild disabled={!(space && document)}>
|
|
157
|
+
<Button>
|
|
158
|
+
<DotsThreeVertical className={getSize(5)} />
|
|
159
|
+
<span className='sr-only'>{t('embedded options label')}</span>
|
|
160
|
+
</Button>
|
|
161
|
+
</DropdownMenu.Trigger>
|
|
162
|
+
</Tooltip.Trigger>
|
|
163
|
+
<DropdownMenu.Content {...overlayAttrs}>
|
|
164
|
+
<DropdownMenu.Viewport>
|
|
165
|
+
<DropdownMenu.Item asChild>
|
|
166
|
+
<a
|
|
167
|
+
target='_blank'
|
|
168
|
+
rel='noreferrer'
|
|
169
|
+
href={
|
|
170
|
+
space && document
|
|
171
|
+
? `${location.origin}/dxos/space/${space?.key.toHex() ?? 'never'}/${document.id}`
|
|
172
|
+
: '#'
|
|
173
|
+
}
|
|
174
|
+
>
|
|
175
|
+
<ArrowSquareOut className={mx('shrink-0', getSize(5))} />
|
|
176
|
+
<span className='grow'>{t('open in composer label', { ns: GITHUB_PLUGIN })}</span>
|
|
177
|
+
</a>
|
|
178
|
+
</DropdownMenu.Item>
|
|
179
|
+
<DropdownMenu.Separator />
|
|
180
|
+
<DropdownMenu.GroupLabel>
|
|
181
|
+
{t('active space label', { ns: SPACE_PLUGIN })}
|
|
182
|
+
<Avatar.Root size={5} variant='circle'>
|
|
183
|
+
<div role='none' className='flex gap-1 mlb-1 items-center'>
|
|
184
|
+
<Avatar.Frame>
|
|
185
|
+
<Avatar.Fallback text={spaceFallbackValue.emoji} />
|
|
186
|
+
</Avatar.Frame>
|
|
187
|
+
<Avatar.Label classNames='text-sm text-[--surface-text]'>
|
|
188
|
+
{name && toLocalizedString(name, t)}
|
|
189
|
+
</Avatar.Label>
|
|
190
|
+
</div>
|
|
191
|
+
</Avatar.Root>
|
|
192
|
+
</DropdownMenu.GroupLabel>
|
|
193
|
+
<DropdownMenu.Item onClick={() => setRenameDialogOpen(true)}>
|
|
194
|
+
<span className='grow'>{t('rename space label', { ns: SPACE_PLUGIN })}</span>
|
|
195
|
+
<PencilSimpleLine className={mx('shrink-0', getSize(5))} />
|
|
196
|
+
</DropdownMenu.Item>
|
|
197
|
+
<DropdownMenu.Item onClick={() => setResolverDialogOpen(true)}>
|
|
198
|
+
<span className='grow'>{t('unset repo space label')}</span>
|
|
199
|
+
<Option className={mx('shrink-0', getSize(5))} />
|
|
200
|
+
</DropdownMenu.Item>
|
|
201
|
+
</DropdownMenu.Viewport>
|
|
202
|
+
<DropdownMenu.Arrow />
|
|
203
|
+
</DropdownMenu.Content>
|
|
204
|
+
<Tooltip.Content {...overlayAttrs}>
|
|
205
|
+
{t('embedded options label')}
|
|
206
|
+
<Tooltip.Arrow />
|
|
207
|
+
</Tooltip.Content>
|
|
208
|
+
</DropdownMenu.Root>
|
|
209
|
+
</Tooltip.Root>
|
|
210
|
+
<ButtonGroup classNames={[!(space && document) && 'shadow-none']}>
|
|
211
|
+
<Button disabled={!(space && document)} onClick={handleSaveAndCloseEmbed}>
|
|
212
|
+
{t('save and close label')}
|
|
213
|
+
</Button>
|
|
214
|
+
<DropdownMenu.Root>
|
|
215
|
+
<DropdownMenu.Trigger asChild disabled={!(space && document)}>
|
|
216
|
+
<Button>
|
|
217
|
+
<CaretDown />
|
|
218
|
+
</Button>
|
|
219
|
+
</DropdownMenu.Trigger>
|
|
220
|
+
<DropdownMenu.Portal>
|
|
221
|
+
<DropdownMenu.Content {...overlayAttrs}>
|
|
222
|
+
<DropdownMenu.Viewport>
|
|
223
|
+
<DropdownMenu.Item onClick={handleSaveAndCloseEmbed} classNames='block'>
|
|
224
|
+
<p>{t('save and close label')}</p>
|
|
225
|
+
<p className={descriptionText}>{t('save and close description')}</p>
|
|
226
|
+
</DropdownMenu.Item>
|
|
227
|
+
<DropdownMenu.Item onClick={handleCloseEmbed} classNames='block'>
|
|
228
|
+
<p>{t('close label', { ns: 'appkit' })}</p>
|
|
229
|
+
<p className={descriptionText}>{t('close embed description')}</p>
|
|
230
|
+
</DropdownMenu.Item>
|
|
231
|
+
</DropdownMenu.Viewport>
|
|
232
|
+
<DropdownMenu.Arrow />
|
|
233
|
+
</DropdownMenu.Content>
|
|
234
|
+
</DropdownMenu.Portal>
|
|
235
|
+
</DropdownMenu.Root>
|
|
236
|
+
</ButtonGroup>
|
|
237
|
+
</div>
|
|
238
|
+
{space && document ? (
|
|
239
|
+
editorViewState === 'preview' ? (
|
|
240
|
+
<Main.Content classNames='min-bs-[100dvh] flex flex-col p-0.5'>
|
|
241
|
+
<GfmPreview
|
|
242
|
+
markdown={document.content?.toString() ?? ''}
|
|
243
|
+
{...(docGhId && { owner: docGhId.owner, repo: docGhId.repo })}
|
|
244
|
+
/>
|
|
245
|
+
</Main.Content>
|
|
246
|
+
) : (
|
|
247
|
+
// TODO(burdon): This will break since model is not defined.
|
|
248
|
+
<Surface role='main' data={{ properties: document, view: 'embedded' }} />
|
|
249
|
+
)
|
|
250
|
+
) : source && id && identityHex ? (
|
|
251
|
+
<Dialog.Root open onOpenChange={() => true}>
|
|
252
|
+
<div role='none' className={defaultTx('dialog.overlay', 'dialog--resolver__overlay', {}, 'static bs-full')}>
|
|
253
|
+
<div
|
|
254
|
+
role='none'
|
|
255
|
+
className={defaultTx(
|
|
256
|
+
'dialog.content',
|
|
257
|
+
'dialog--resolver__content',
|
|
258
|
+
{},
|
|
259
|
+
'p-2 bs-72 flex flex-col shadow-none bg-transparent',
|
|
260
|
+
)}
|
|
261
|
+
>
|
|
262
|
+
<ResolverDialog handleCreateSpace={handleCreateSpace} handleJoinSpace={handleJoinSpace} />
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</Dialog.Root>
|
|
266
|
+
) : null}
|
|
267
|
+
{space && (
|
|
268
|
+
<Dialog.Root open={renameDialogOpen} onOpenChange={setRenameDialogOpen}>
|
|
269
|
+
<Dialog.Overlay classNames='backdrop-blur'>
|
|
270
|
+
<Dialog.Content>
|
|
271
|
+
<Surface role='dialog' data={{ content: 'dxos.org/plugin/space/RenameSpaceDialog', subject: space }} />
|
|
272
|
+
</Dialog.Content>
|
|
273
|
+
</Dialog.Overlay>
|
|
274
|
+
</Dialog.Root>
|
|
275
|
+
)}
|
|
276
|
+
<Dialog.Root open={resolverDialogOpen} onOpenChange={setResolverDialogOpen}>
|
|
277
|
+
<Dialog.Overlay classNames='backdrop-blur'>
|
|
278
|
+
<Dialog.Content>
|
|
279
|
+
<ResolverDialog handleCreateSpace={handleCreateSpace} handleJoinSpace={handleJoinSpace} />
|
|
280
|
+
</Dialog.Content>
|
|
281
|
+
</Dialog.Overlay>
|
|
282
|
+
</Dialog.Root>
|
|
283
|
+
</DensityProvider>
|
|
284
|
+
</>
|
|
285
|
+
);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const EmbeddedMain = () => {
|
|
289
|
+
return (
|
|
290
|
+
<SpaceResolverProvider>
|
|
291
|
+
<DocumentResolverProvider>
|
|
292
|
+
<EmbeddedLayoutImpl />
|
|
293
|
+
</DocumentResolverProvider>
|
|
294
|
+
</SpaceResolverProvider>
|
|
295
|
+
);
|
|
296
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import 'github-markdown-css/github-markdown.css';
|
|
6
|
+
import DOMPurify from 'dompurify';
|
|
7
|
+
import React, { useEffect, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { useTranslation } from '@dxos/react-ui';
|
|
10
|
+
|
|
11
|
+
import { GITHUB_PLUGIN } from '../../meta';
|
|
12
|
+
import { GitHubSettings, useOctokitContext } from '../GithubApiProviders';
|
|
13
|
+
import { Loading } from '../Loading';
|
|
14
|
+
|
|
15
|
+
const defaultOptions: Parameters<typeof DOMPurify.sanitize>[1] = {
|
|
16
|
+
ALLOWED_TAGS: [
|
|
17
|
+
'span',
|
|
18
|
+
'div',
|
|
19
|
+
'b',
|
|
20
|
+
'i',
|
|
21
|
+
'em',
|
|
22
|
+
'strong',
|
|
23
|
+
'a',
|
|
24
|
+
'p',
|
|
25
|
+
'h1',
|
|
26
|
+
'h2',
|
|
27
|
+
'h3',
|
|
28
|
+
'h4',
|
|
29
|
+
'h5',
|
|
30
|
+
'h6',
|
|
31
|
+
'table',
|
|
32
|
+
'td',
|
|
33
|
+
'th',
|
|
34
|
+
'tr',
|
|
35
|
+
'blockquote',
|
|
36
|
+
'ul',
|
|
37
|
+
'ol',
|
|
38
|
+
'li',
|
|
39
|
+
'dd',
|
|
40
|
+
'tt',
|
|
41
|
+
'dl',
|
|
42
|
+
'dt',
|
|
43
|
+
'details',
|
|
44
|
+
'figcaption',
|
|
45
|
+
'figure',
|
|
46
|
+
'summary',
|
|
47
|
+
'abbr',
|
|
48
|
+
'dfn',
|
|
49
|
+
'mark',
|
|
50
|
+
'sub',
|
|
51
|
+
'sup',
|
|
52
|
+
'img',
|
|
53
|
+
'code',
|
|
54
|
+
'kbd',
|
|
55
|
+
'pre',
|
|
56
|
+
'samp',
|
|
57
|
+
'hr',
|
|
58
|
+
'input',
|
|
59
|
+
'pre',
|
|
60
|
+
'del',
|
|
61
|
+
'g-emoji',
|
|
62
|
+
'label',
|
|
63
|
+
],
|
|
64
|
+
ALLOWED_ATTR: ['class', 'href', 'target', 'hidden', 'title', 'type', 'role', 'align', 'data-footnote-ref'],
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const sanitize = (dirty: string, options: Partial<Parameters<typeof DOMPurify.sanitize>[1]>) => ({
|
|
68
|
+
__html: DOMPurify.sanitize(dirty, { ...defaultOptions, ...options }) as string,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export type GfmPreviewProps = {
|
|
72
|
+
markdown: string;
|
|
73
|
+
owner?: string;
|
|
74
|
+
repo?: string;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const GfmPreview = ({ markdown, owner, repo }: GfmPreviewProps) => {
|
|
78
|
+
const [html, setHtml] = useState('');
|
|
79
|
+
const { octokit } = useOctokitContext();
|
|
80
|
+
const { t } = useTranslation(GITHUB_PLUGIN);
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (octokit && markdown) {
|
|
84
|
+
void octokit
|
|
85
|
+
.request('POST /markdown', {
|
|
86
|
+
text: markdown,
|
|
87
|
+
...(owner && repo && { context: `${owner}/${repo}` }),
|
|
88
|
+
})
|
|
89
|
+
.then(
|
|
90
|
+
({ data }) => setHtml(data),
|
|
91
|
+
() => {},
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}, [markdown, octokit]);
|
|
95
|
+
|
|
96
|
+
return html ? (
|
|
97
|
+
<>
|
|
98
|
+
<style>{'.markdown-body ol, .markdown-body ul {list-style-type: disc; list-style-position: outside;}'}</style>
|
|
99
|
+
<article
|
|
100
|
+
className='markdown-body grow is-full max-is-[980px] mli-auto p-[15px] sm:pli-[45px] sm:plb-[30px]'
|
|
101
|
+
dangerouslySetInnerHTML={sanitize(html, {})}
|
|
102
|
+
/>
|
|
103
|
+
</>
|
|
104
|
+
) : (
|
|
105
|
+
<div role='none' className='mli-auto max-is-md pli-2 text-center'>
|
|
106
|
+
{!octokit && <p className='mlb-4 text-lg font-medium'>{t('empty github pat message')}</p>}
|
|
107
|
+
{octokit ? <Loading label={t('loading preview message')} /> : <GitHubSettings />}
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import { Button, Dialog, Input, Trans, useTranslation } from '@dxos/react-ui';
|
|
9
|
+
|
|
10
|
+
import { useOctokitContext } from './GithubApiProviders';
|
|
11
|
+
import { GITHUB_PLUGIN } from '../meta';
|
|
12
|
+
import type { ExportViewState, GhFileIdentifier, GhIdentifier } from '../types';
|
|
13
|
+
|
|
14
|
+
export const ExportDialog = ({
|
|
15
|
+
type,
|
|
16
|
+
target,
|
|
17
|
+
docGhId,
|
|
18
|
+
}: {
|
|
19
|
+
type: ExportViewState;
|
|
20
|
+
target: string | null;
|
|
21
|
+
docGhId: GhIdentifier;
|
|
22
|
+
}) => {
|
|
23
|
+
// TODO(burdon): Model removed.
|
|
24
|
+
const content = '';
|
|
25
|
+
|
|
26
|
+
const { octokit } = useOctokitContext();
|
|
27
|
+
const { t } = useTranslation(GITHUB_PLUGIN);
|
|
28
|
+
const [exportViewState, setExportViewState] = useState<ExportViewState>(type);
|
|
29
|
+
const [ghResponseUrl, setGhResponseUrl] = useState<string | null>(target);
|
|
30
|
+
const [ghBranchValue, setGhBranchValue] = useState('');
|
|
31
|
+
const [ghMessageValue, setGhMessageValue] = useState('');
|
|
32
|
+
|
|
33
|
+
const exportGhFileContent = useCallback(async () => {
|
|
34
|
+
if (octokit && docGhId && 'path' in docGhId && content) {
|
|
35
|
+
const branchName = ghBranchValue || t('github branch name placeholder');
|
|
36
|
+
const commitMessage = ghMessageValue || t('github commit message placeholder');
|
|
37
|
+
setExportViewState('pending');
|
|
38
|
+
try {
|
|
39
|
+
const { owner, repo, path, ref } = docGhId as GhFileIdentifier;
|
|
40
|
+
const { data: fileData } = await octokit.rest.repos.getContent({ owner, repo, path });
|
|
41
|
+
if (Array.isArray(fileData) || fileData.type !== 'file') {
|
|
42
|
+
log.error('Attempted to export to a destination in Github that is not a file.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const { sha: fileSha } = fileData;
|
|
46
|
+
const {
|
|
47
|
+
data: {
|
|
48
|
+
object: { sha: baseSha },
|
|
49
|
+
},
|
|
50
|
+
} = await octokit.rest.git.getRef({ owner, repo, ref: `heads/${ref}` });
|
|
51
|
+
await octokit.rest.git.createRef({
|
|
52
|
+
owner,
|
|
53
|
+
repo,
|
|
54
|
+
ref: `refs/heads/${branchName}`,
|
|
55
|
+
sha: baseSha,
|
|
56
|
+
});
|
|
57
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
58
|
+
owner,
|
|
59
|
+
repo,
|
|
60
|
+
path,
|
|
61
|
+
message: commitMessage,
|
|
62
|
+
branch: branchName,
|
|
63
|
+
sha: fileSha,
|
|
64
|
+
content: btoa(content),
|
|
65
|
+
});
|
|
66
|
+
const {
|
|
67
|
+
data: { html_url: prUrl },
|
|
68
|
+
} = await octokit.rest.pulls.create({
|
|
69
|
+
owner,
|
|
70
|
+
repo,
|
|
71
|
+
head: branchName,
|
|
72
|
+
base: ref,
|
|
73
|
+
title: commitMessage,
|
|
74
|
+
});
|
|
75
|
+
setGhResponseUrl(prUrl);
|
|
76
|
+
setExportViewState('response');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
log.error('Failed to export to Github file', err);
|
|
79
|
+
setExportViewState('create-pr');
|
|
80
|
+
setGhResponseUrl(null);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
log.error('Not prepared to export to Github file when requested.');
|
|
84
|
+
setGhResponseUrl(null);
|
|
85
|
+
}
|
|
86
|
+
}, [octokit, docGhId, content, ghBranchValue, ghMessageValue, t]);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Dialog.Content>
|
|
90
|
+
<Dialog.Title>{t('confirm export title')}</Dialog.Title>
|
|
91
|
+
{exportViewState === 'response' ? (
|
|
92
|
+
<>
|
|
93
|
+
<p>
|
|
94
|
+
<Trans
|
|
95
|
+
{...{
|
|
96
|
+
t,
|
|
97
|
+
i18nKey: 'export to github success message',
|
|
98
|
+
values: { linkText: ghResponseUrl },
|
|
99
|
+
components: {
|
|
100
|
+
resultStyle: <span className='text-success-600 dark:text-success-300'>_</span>,
|
|
101
|
+
prLink: (
|
|
102
|
+
<a
|
|
103
|
+
href={ghResponseUrl!}
|
|
104
|
+
target='_blank'
|
|
105
|
+
rel='noreferrer'
|
|
106
|
+
className='text-primary-600 dark:text-primary-300 hover:text-primary-700 dark:hover:text-primary-400'
|
|
107
|
+
>
|
|
108
|
+
_
|
|
109
|
+
</a>
|
|
110
|
+
),
|
|
111
|
+
},
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
</p>
|
|
115
|
+
<div role='none' className='flex justify-end'>
|
|
116
|
+
<Dialog.Close asChild>
|
|
117
|
+
<Button variant='primary' onClick={() => setExportViewState(null)}>
|
|
118
|
+
{t('done label', { ns: 'os' })}
|
|
119
|
+
</Button>
|
|
120
|
+
</Dialog.Close>
|
|
121
|
+
</div>
|
|
122
|
+
</>
|
|
123
|
+
) : (
|
|
124
|
+
<div role='none' className='mbs-2 space-b-2'>
|
|
125
|
+
<Input.Root>
|
|
126
|
+
<Input.Label>{t('github branch name label')}</Input.Label>
|
|
127
|
+
<Input.TextInput
|
|
128
|
+
autoFocus
|
|
129
|
+
classNames='font-mono'
|
|
130
|
+
disabled={exportViewState === 'pending'}
|
|
131
|
+
placeholder={t('github branch name placeholder')}
|
|
132
|
+
value={ghBranchValue}
|
|
133
|
+
onChange={({ target: { value } }) => setGhBranchValue(value)}
|
|
134
|
+
/>
|
|
135
|
+
</Input.Root>
|
|
136
|
+
<Input.Root>
|
|
137
|
+
<Input.Label>{t('github commit message label')}</Input.Label>
|
|
138
|
+
<Input.TextArea
|
|
139
|
+
disabled={exportViewState === 'pending'}
|
|
140
|
+
placeholder={t('github commit message placeholder')}
|
|
141
|
+
value={ghMessageValue}
|
|
142
|
+
onChange={({ target: { value } }) => setGhMessageValue(value)}
|
|
143
|
+
/>
|
|
144
|
+
</Input.Root>
|
|
145
|
+
<div role='none' className='flex justify-end gap-2'>
|
|
146
|
+
<Dialog.Close asChild>
|
|
147
|
+
<Button onClick={() => setExportViewState(null)}>{t('close label', { ns: 'os' })}</Button>
|
|
148
|
+
</Dialog.Close>
|
|
149
|
+
<Button disabled={exportViewState === 'pending'} variant='primary' onClick={() => exportGhFileContent()}>
|
|
150
|
+
{t('continue label', { ns: 'os' })}
|
|
151
|
+
</Button>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
</Dialog.Content>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { ArrowSquareOut } from '@phosphor-icons/react';
|
|
6
|
+
import React, { type PropsWithChildren, useEffect, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { SettingsValue } from '@dxos/plugin-settings';
|
|
9
|
+
import { Link, Input, Trans, useTranslation, useId } from '@dxos/react-ui';
|
|
10
|
+
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
11
|
+
|
|
12
|
+
import { useOctokitContext } from './OctokitProvider';
|
|
13
|
+
import { GITHUB_PLUGIN } from '../../meta';
|
|
14
|
+
|
|
15
|
+
// TODO(burdon): Factor out with PluginList.
|
|
16
|
+
const ExternalLink = ({ children }: PropsWithChildren<{}>) => {
|
|
17
|
+
const { t } = useTranslation(GITHUB_PLUGIN);
|
|
18
|
+
const descriptionId = useId('link--external');
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<Link href={t('github pat description href')} target='_blank' rel='noreferrer' aria-describedby={descriptionId}>
|
|
22
|
+
{children}
|
|
23
|
+
<ArrowSquareOut weight='bold' className={mx(getSize(3), 'inline-block leading-none -mbs-0.5 mli-px')} />
|
|
24
|
+
</Link>
|
|
25
|
+
<span className='sr-only' id={descriptionId}>
|
|
26
|
+
{t('target blank description', { ns: GITHUB_PLUGIN })}
|
|
27
|
+
</span>
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// TODO(burdon): Pass in settings.
|
|
33
|
+
export const GitHubSettings = () => {
|
|
34
|
+
const { t } = useTranslation(GITHUB_PLUGIN);
|
|
35
|
+
const { pat, setPat } = useOctokitContext();
|
|
36
|
+
const [patValue, setPatValue] = useState(pat);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setPatValue(pat);
|
|
40
|
+
}, [pat]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
void setPat(patValue);
|
|
44
|
+
}, [patValue]);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<SettingsValue
|
|
49
|
+
label={t('github pat label')}
|
|
50
|
+
description={
|
|
51
|
+
<Trans
|
|
52
|
+
{...{
|
|
53
|
+
t,
|
|
54
|
+
i18nKey: 'github pat description',
|
|
55
|
+
components: {
|
|
56
|
+
docsLink: <ExternalLink />,
|
|
57
|
+
},
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
<Input.TextInput
|
|
63
|
+
autoFocus
|
|
64
|
+
spellCheck={false}
|
|
65
|
+
classNames='font-mono mlb-1'
|
|
66
|
+
value={patValue ?? ''}
|
|
67
|
+
onChange={({ target: { value } }) => setPatValue(value)}
|
|
68
|
+
/>
|
|
69
|
+
</SettingsValue>
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
};
|