feat: editor type + fix removing integrations
This commit is contained in:
parent
4907bb3572
commit
f10c7f56a4
|
|
@ -33,7 +33,10 @@ import {
|
|||
} from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { timer } from '@gitroom/helpers/utils/timer';
|
||||
import { TelegramProvider } from '@gitroom/nestjs-libraries/integrations/social/telegram.provider';
|
||||
import { AuthorizationActions, Sections } from '@gitroom/backend/services/auth/permissions/permission.exception.class';
|
||||
import {
|
||||
AuthorizationActions,
|
||||
Sections,
|
||||
} from '@gitroom/backend/services/auth/permissions/permission.exception.class';
|
||||
|
||||
@ApiTags('Integrations')
|
||||
@Controller('/integrations')
|
||||
|
|
@ -95,6 +98,7 @@ export class IntegrationsController {
|
|||
id: p.id,
|
||||
internalId: p.internalId,
|
||||
disabled: p.disabled,
|
||||
editor: findIntegration.editor,
|
||||
picture: p.picture || '/no-picture.jpg',
|
||||
identifier: p.providerIdentifier,
|
||||
inBetweenSteps: p.inBetweenSteps,
|
||||
|
|
@ -255,85 +259,62 @@ export class IntegrationsController {
|
|||
throw new Error('Invalid integration');
|
||||
}
|
||||
|
||||
if (getIntegration.type === 'social') {
|
||||
const integrationProvider = this._integrationManager.getSocialIntegration(
|
||||
getIntegration.providerIdentifier
|
||||
);
|
||||
if (!integrationProvider) {
|
||||
throw new Error('Invalid provider');
|
||||
}
|
||||
|
||||
if (integrationProvider[body.name]) {
|
||||
try {
|
||||
const load = await integrationProvider[body.name](
|
||||
getIntegration.token,
|
||||
body.data,
|
||||
getIntegration.internalId,
|
||||
getIntegration
|
||||
);
|
||||
|
||||
return load;
|
||||
} catch (err) {
|
||||
if (err instanceof RefreshToken) {
|
||||
const { accessToken, refreshToken, expiresIn, additionalSettings } =
|
||||
await integrationProvider.refreshToken(
|
||||
getIntegration.refreshToken
|
||||
);
|
||||
|
||||
if (accessToken) {
|
||||
await this._integrationService.createOrUpdateIntegration(
|
||||
additionalSettings,
|
||||
!!integrationProvider.oneTimeToken,
|
||||
getIntegration.organizationId,
|
||||
getIntegration.name,
|
||||
getIntegration.picture!,
|
||||
'social',
|
||||
getIntegration.internalId,
|
||||
getIntegration.providerIdentifier,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
expiresIn
|
||||
);
|
||||
|
||||
getIntegration.token = accessToken;
|
||||
|
||||
if (integrationProvider.refreshWait) {
|
||||
await timer(10000);
|
||||
}
|
||||
return this.functionIntegration(org, body);
|
||||
} else {
|
||||
await this._integrationService.disconnectChannel(
|
||||
org.id,
|
||||
getIntegration
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw new Error('Function not found');
|
||||
const integrationProvider = this._integrationManager.getSocialIntegration(
|
||||
getIntegration.providerIdentifier
|
||||
);
|
||||
if (!integrationProvider) {
|
||||
throw new Error('Invalid provider');
|
||||
}
|
||||
|
||||
if (getIntegration.type === 'article') {
|
||||
const integrationProvider =
|
||||
this._integrationManager.getArticlesIntegration(
|
||||
getIntegration.providerIdentifier
|
||||
);
|
||||
if (!integrationProvider) {
|
||||
throw new Error('Invalid provider');
|
||||
}
|
||||
|
||||
if (integrationProvider[body.name]) {
|
||||
return integrationProvider[body.name](
|
||||
if (integrationProvider[body.name]) {
|
||||
try {
|
||||
const load = await integrationProvider[body.name](
|
||||
getIntegration.token,
|
||||
body.data,
|
||||
getIntegration.internalId
|
||||
getIntegration.internalId,
|
||||
getIntegration
|
||||
);
|
||||
|
||||
return load;
|
||||
} catch (err) {
|
||||
if (err instanceof RefreshToken) {
|
||||
const { accessToken, refreshToken, expiresIn, additionalSettings } =
|
||||
await integrationProvider.refreshToken(getIntegration.refreshToken);
|
||||
|
||||
if (accessToken) {
|
||||
await this._integrationService.createOrUpdateIntegration(
|
||||
additionalSettings,
|
||||
!!integrationProvider.oneTimeToken,
|
||||
getIntegration.organizationId,
|
||||
getIntegration.name,
|
||||
getIntegration.picture!,
|
||||
'social',
|
||||
getIntegration.internalId,
|
||||
getIntegration.providerIdentifier,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
expiresIn
|
||||
);
|
||||
|
||||
getIntegration.token = accessToken;
|
||||
|
||||
if (integrationProvider.refreshWait) {
|
||||
await timer(10000);
|
||||
}
|
||||
return this.functionIntegration(org, body);
|
||||
} else {
|
||||
await this._integrationService.disconnectChannel(
|
||||
org.id,
|
||||
getIntegration
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
throw new Error('Function not found');
|
||||
}
|
||||
throw new Error('Function not found');
|
||||
}
|
||||
|
||||
@Post('/social/:integration/connect')
|
||||
|
|
|
|||
|
|
@ -543,4 +543,13 @@ html[dir='rtl'] [dir='ltr'] {
|
|||
.ProseMirror .mention {
|
||||
font-weight: bold;
|
||||
color: #ae8afc;
|
||||
}
|
||||
|
||||
.ProseMirror ul, .preview ul {
|
||||
list-style: disc;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.preview ul, .preview li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
@ -68,6 +68,7 @@ export interface Integrations {
|
|||
id: string;
|
||||
disabled?: boolean;
|
||||
inBetweenSteps: boolean;
|
||||
editor: 'normal' | 'markdown' | 'html';
|
||||
display: string;
|
||||
identifier: string;
|
||||
type: string;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ export const GeneralPreviewComponent: FC<{
|
|||
return { text: finalValue, images: p.image };
|
||||
});
|
||||
|
||||
console.log(renderContent);
|
||||
return (
|
||||
<div className={clsx('w-full md:w-[555px] px-[16px]')}>
|
||||
<div className="w-full h-full relative flex flex-col">
|
||||
|
|
@ -103,8 +102,8 @@ export const GeneralPreviewComponent: FC<{
|
|||
: integration?.display || '@username'}
|
||||
</div>
|
||||
</div>
|
||||
<pre
|
||||
className={clsx('text-wrap', interClass)}
|
||||
<div
|
||||
className={clsx('text-wrap whitespace-pre', 'preview', interClass)}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: value.text,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
'use client';
|
||||
|
||||
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
|
||||
import { useCallback } from 'react';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export const useIntegrationList = () => {
|
||||
const fetch = useFetch();
|
||||
|
||||
const load = useCallback(async (path: string) => {
|
||||
return (await (await fetch(path)).json()).integrations;
|
||||
}, []);
|
||||
|
||||
return useSWR('/integrations/list', load, {
|
||||
fallbackData: [],
|
||||
});
|
||||
};
|
||||
|
|
@ -24,6 +24,8 @@ import { GeneratorComponent } from './generator/generator';
|
|||
import { useVariables } from '@gitroom/react/helpers/variable.context';
|
||||
import { NewPost } from '@gitroom/frontend/components/launches/new.post';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import { useIntegrationList } from '@gitroom/frontend/components/launches/helpers/use.integration.list';
|
||||
|
||||
interface MenuComponentInterface {
|
||||
refreshChannel: (
|
||||
integration: Integration & {
|
||||
|
|
@ -283,16 +285,13 @@ export const LaunchesComponent = () => {
|
|||
const fireEvents = useFireEvents();
|
||||
const t = useT();
|
||||
const [reload, setReload] = useState(false);
|
||||
const load = useCallback(async (path: string) => {
|
||||
return (await (await fetch(path)).json()).integrations;
|
||||
}, []);
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
data: integrations,
|
||||
mutate,
|
||||
} = useSWR('/integrations/list', load, {
|
||||
fallbackData: [],
|
||||
});
|
||||
} = useIntegrationList();
|
||||
|
||||
const totalNonDisabledChannels = useMemo(() => {
|
||||
return (
|
||||
integrations?.filter((integration: any) => !integration.disabled)
|
||||
|
|
@ -453,7 +452,9 @@ export const LaunchesComponent = () => {
|
|||
user?.tier?.ai &&
|
||||
billingEnabled && <GeneratorComponent />}
|
||||
<div className="mt-[5px]">
|
||||
{process.env.NEXT_PUBLIC_VERSION ? `${process.env.NEXT_PUBLIC_VERSION}` : ''}
|
||||
{process.env.NEXT_PUBLIC_VERSION
|
||||
? `${process.env.NEXT_PUBLIC_VERSION}`
|
||||
: ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
|
|||
setCurrent,
|
||||
internal,
|
||||
setTags,
|
||||
setEditor,
|
||||
} = useLaunchStore(
|
||||
useShallow((state) => ({
|
||||
reset: state.reset,
|
||||
|
|
@ -124,6 +125,7 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
|
|||
global: state.global,
|
||||
internal: state.internal,
|
||||
setTags: state.setTags,
|
||||
setEditor: state.setEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
|
|
@ -154,6 +156,9 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
|
|||
);
|
||||
setCurrent(existingData.integration);
|
||||
}
|
||||
else {
|
||||
setEditor('normal');
|
||||
}
|
||||
|
||||
if (props.focusedChannel) {
|
||||
setCurrent(props.focusedChannel);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
'use client';
|
||||
|
||||
import { FC, useCallback } from 'react';
|
||||
|
||||
export const Bullets: FC<{
|
||||
editor: any;
|
||||
currentValue: string;
|
||||
}> = ({ editor }) => {
|
||||
const bullet = () => {
|
||||
editor.commands.toggleBulletList();
|
||||
};
|
||||
return (
|
||||
<div
|
||||
onClick={bullet}
|
||||
className="select-none cursor-pointer w-[40px] p-[5px] text-center"
|
||||
>
|
||||
A
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -45,6 +45,8 @@ import Paragraph from '@tiptap/extension-paragraph';
|
|||
import Underline from '@tiptap/extension-underline';
|
||||
import { stripHtmlValidation } from '@gitroom/helpers/utils/strip.html.validation';
|
||||
import { History } from '@tiptap/extension-history';
|
||||
import { BulletList, ListItem } from '@tiptap/extension-list';
|
||||
import { Bullets } from '@gitroom/frontend/components/new-launch/bullets.component';
|
||||
|
||||
const InterceptBoldShortcut = Extension.create({
|
||||
name: 'preventBoldWithUnderline',
|
||||
|
|
@ -147,6 +149,9 @@ export const EditorWrapper: FC<{
|
|||
totalChars,
|
||||
postComment,
|
||||
dummy,
|
||||
editor,
|
||||
loadedState,
|
||||
setLoadedState,
|
||||
} = useLaunchStore(
|
||||
useShallow((state) => ({
|
||||
internal: state.internal.find((p) => p.integration.id === state.current),
|
||||
|
|
@ -172,6 +177,9 @@ export const EditorWrapper: FC<{
|
|||
appendInternalValueMedia: state.appendInternalValueMedia,
|
||||
appendGlobalValueMedia: state.appendGlobalValueMedia,
|
||||
postComment: state.postComment,
|
||||
editor: state.editor,
|
||||
loadedState: state.loaded,
|
||||
setLoadedState: state.setLoaded
|
||||
}))
|
||||
);
|
||||
|
||||
|
|
@ -179,12 +187,13 @@ export const EditorWrapper: FC<{
|
|||
const [loaded, setLoaded] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (loaded) {
|
||||
if (loaded && loadedState) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadedState(true);
|
||||
setLoaded(true);
|
||||
}, [loaded]);
|
||||
}, [loaded, loadedState]);
|
||||
|
||||
const canEdit = useMemo(() => {
|
||||
return current === 'global' || !!internal;
|
||||
|
|
@ -341,7 +350,7 @@ export const EditorWrapper: FC<{
|
|||
[current, global, internal]
|
||||
);
|
||||
|
||||
if (!loaded) {
|
||||
if (!loaded || !loadedState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -371,6 +380,7 @@ export const EditorWrapper: FC<{
|
|||
<div className="flex gap-[5px]">
|
||||
<div className="flex-1">
|
||||
<Editor
|
||||
editorType={editor}
|
||||
allValues={items}
|
||||
onChange={changeValue(index)}
|
||||
key={index}
|
||||
|
|
@ -451,6 +461,7 @@ export const EditorWrapper: FC<{
|
|||
};
|
||||
|
||||
export const Editor: FC<{
|
||||
editorType?: 'normal' | 'markdown' | 'html';
|
||||
totalPosts: number;
|
||||
value: string;
|
||||
num?: number;
|
||||
|
|
@ -466,6 +477,7 @@ export const Editor: FC<{
|
|||
dummy: boolean;
|
||||
}> = (props) => {
|
||||
const {
|
||||
editorType = 'normal',
|
||||
allValues,
|
||||
pictures,
|
||||
setImages,
|
||||
|
|
@ -520,7 +532,24 @@ export const Editor: FC<{
|
|||
[uppy]
|
||||
);
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
|
||||
const { getRootProps, isDragActive } = useDropzone({ onDrop });
|
||||
|
||||
const editorOptions = useMemo(() => {
|
||||
if (editorType === 'normal') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const list = [];
|
||||
|
||||
if (
|
||||
editorType === ('markdown' as const) ||
|
||||
editorType === ('html' as const)
|
||||
) {
|
||||
list.push(BulletList, ListItem);
|
||||
}
|
||||
|
||||
return list;
|
||||
}, [editorType]);
|
||||
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
|
|
@ -536,6 +565,7 @@ export const Editor: FC<{
|
|||
depth: 100, // default is 100
|
||||
newGroupDelay: 100, // default is 500ms
|
||||
}),
|
||||
...editorOptions,
|
||||
],
|
||||
content: props.value || '',
|
||||
shouldRerenderOnTransaction: true,
|
||||
|
|
@ -590,6 +620,9 @@ export const Editor: FC<{
|
|||
<SignatureBox editor={editor} />
|
||||
<UText editor={editor} currentValue={props.value!} />
|
||||
<BoldText editor={editor} currentValue={props.value!} />
|
||||
{(editorType === 'markdown' || editorType === 'html') && (
|
||||
<Bullets editor={editor} currentValue={props.value!} />
|
||||
)}
|
||||
<div
|
||||
className="select-none cursor-pointer w-[40px] p-[5px] text-center"
|
||||
onClick={() => setEmojiPickerOpen(!emojiPickerOpen)}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ export const withProvider = function <T extends object>(params: {
|
|||
const fetch = useFetch();
|
||||
const {
|
||||
current,
|
||||
integrations,
|
||||
selectedIntegration,
|
||||
setCurrent,
|
||||
internal,
|
||||
|
|
@ -87,6 +86,7 @@ export const withProvider = function <T extends object>(params: {
|
|||
justCurrent,
|
||||
allIntegrations,
|
||||
setPostComment,
|
||||
setEditor,
|
||||
dummy,
|
||||
} = useLaunchStore(
|
||||
useShallow((state) => ({
|
||||
|
|
@ -104,6 +104,7 @@ export const withProvider = function <T extends object>(params: {
|
|||
setCurrent: state.setCurrent,
|
||||
setTotalChars: state.setTotalChars,
|
||||
setPostComment: state.setPostComment,
|
||||
setEditor: state.setEditor,
|
||||
selectedIntegration: state.selectedIntegrations.find(
|
||||
(p) => p.integration.id === props.id
|
||||
),
|
||||
|
|
@ -118,9 +119,11 @@ export const withProvider = function <T extends object>(params: {
|
|||
if (isGlobal) {
|
||||
setPostComment(PostComment.ALL);
|
||||
setTotalChars(0);
|
||||
setEditor('normal');
|
||||
}
|
||||
|
||||
if (current) {
|
||||
setEditor(selectedIntegration?.integration.editor);
|
||||
setPostComment(postComment);
|
||||
setTotalChars(
|
||||
typeof maximumCharacters === 'number'
|
||||
|
|
@ -246,25 +249,27 @@ export const withProvider = function <T extends object>(params: {
|
|||
{t('preview', 'Preview')}
|
||||
</Button>
|
||||
</div>
|
||||
{current && (!!SettingsComponent || !!data?.internalPlugs?.length) && (
|
||||
<div className="flex-1 flex">
|
||||
<Button
|
||||
onClick={() => setTab(1)}
|
||||
secondary={tab !== 1}
|
||||
className="rounded-[4px] flex-1 overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
{t('settings', 'Settings')} (
|
||||
{capitalize(
|
||||
selectedIntegration.integration.identifier.split('-')[0]
|
||||
)}
|
||||
)
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{current &&
|
||||
(!!SettingsComponent || !!data?.internalPlugs?.length) && (
|
||||
<div className="flex-1 flex">
|
||||
<Button
|
||||
onClick={() => setTab(1)}
|
||||
secondary={tab !== 1}
|
||||
className="rounded-[4px] flex-1 overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
{t('settings', 'Settings')} (
|
||||
{capitalize(
|
||||
selectedIntegration.integration.identifier.split('-')[0]
|
||||
)}
|
||||
)
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{current && (tab === 0 ||
|
||||
(!SettingsComponent && !data?.internalPlugs?.length)) &&
|
||||
{current &&
|
||||
(tab === 0 ||
|
||||
(!SettingsComponent && !data?.internalPlugs?.length)) &&
|
||||
!value?.[0]?.content?.length && (
|
||||
<div>
|
||||
{t(
|
||||
|
|
|
|||
|
|
@ -24,11 +24,12 @@ import NostrProvider from '@gitroom/frontend/components/new-launch/providers/nos
|
|||
import VkProvider from '@gitroom/frontend/components/new-launch/providers/vk/vk.provider';
|
||||
import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import React, { createRef, FC, forwardRef, useImperativeHandle } from 'react';
|
||||
import React, { FC, forwardRef, useEffect, useImperativeHandle } from 'react';
|
||||
import { GeneralPreviewComponent } from '@gitroom/frontend/components/launches/general.preview.component';
|
||||
import { IntegrationContext } from '@gitroom/frontend/components/launches/helpers/use.integration';
|
||||
import { Button } from '@gitroom/react/form/button';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import { PostComment } from '@gitroom/frontend/components/new-launch/providers/high.order.provider';
|
||||
|
||||
export const Providers = [
|
||||
{
|
||||
|
|
@ -154,8 +155,10 @@ export const ShowAllProviders = forwardRef((props, ref) => {
|
|||
);
|
||||
},
|
||||
triggerAll: () => {
|
||||
return selectedIntegrations.map(async (p) => await p.ref?.current.trigger());
|
||||
}
|
||||
return selectedIntegrations.map(
|
||||
async (p) => await p.ref?.current.trigger()
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
|
|
@ -176,15 +179,18 @@ export const ShowAllProviders = forwardRef((props, ref) => {
|
|||
>
|
||||
<div className="flex gap-[4px] mb-[20px]">
|
||||
<div className="flex-1 flex">
|
||||
<Button
|
||||
className="rounded-[4px] flex-1 overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
<Button className="rounded-[4px] flex-1 overflow-hidden whitespace-nowrap">
|
||||
{t('preview', 'Preview')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{global?.[0]?.content?.length === 0 ? (
|
||||
<div>{t('start_writing_your_post', 'Start writing your post for a preview')}</div>
|
||||
<div>
|
||||
{t(
|
||||
'start_writing_your_post',
|
||||
'Start writing your post for a preview'
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<GeneralPreviewComponent maximumCharacters={100000000} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ interface SelectedIntegrations {
|
|||
}
|
||||
|
||||
interface StoreState {
|
||||
editor: undefined | 'normal' | 'markdown' | 'html';
|
||||
loaded: boolean;
|
||||
date: dayjs.Dayjs;
|
||||
postComment: PostComment;
|
||||
dummy: boolean;
|
||||
|
|
@ -118,9 +120,13 @@ interface StoreState {
|
|||
setPostComment: (postComment: PostComment) => void;
|
||||
setActivateExitButton?: (activateExitButton: boolean) => void;
|
||||
setDummy: (dummy: boolean) => void;
|
||||
setEditor: (editor: 'normal' | 'markdown' | 'html') => void;
|
||||
setLoaded?: (loaded: boolean) => void;
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
editor: undefined as undefined,
|
||||
loaded: true,
|
||||
dummy: false,
|
||||
activateExitButton: true,
|
||||
date: dayjs(),
|
||||
|
|
@ -154,13 +160,22 @@ export const useLaunchStore = create<StoreState>()((set) => ({
|
|||
);
|
||||
|
||||
if (existing) {
|
||||
const selectedList = state.selectedIntegrations.filter(
|
||||
(s, index) => s.integration.id !== existing.integration.id
|
||||
);
|
||||
|
||||
return {
|
||||
...(existing.integration.id === state.current
|
||||
? { current: 'global' }
|
||||
: {}),
|
||||
selectedIntegrations: state.selectedIntegrations.filter(
|
||||
(s, index) => s.integration.id !== existing.integration.id
|
||||
),
|
||||
loaded: false,
|
||||
selectedIntegrations: selectedList,
|
||||
...(selectedList.length === 0
|
||||
? {
|
||||
current: 'global',
|
||||
editor: 'normal',
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -512,4 +527,12 @@ export const useLaunchStore = create<StoreState>()((set) => ({
|
|||
set((state) => ({
|
||||
dummy,
|
||||
})),
|
||||
setEditor: (editor: 'normal' | 'markdown' | 'html') =>
|
||||
set((state) => ({
|
||||
editor,
|
||||
})),
|
||||
setLoaded: (loaded: boolean) =>
|
||||
set((state) => ({
|
||||
loaded,
|
||||
})),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -145,11 +145,11 @@ export const stripHtmlValidation = (
|
|||
.replace(/<\/p>/gi, '');
|
||||
|
||||
if (replaceBold) {
|
||||
return striptags(convertLinkedinMention(convertToAscii(html)));
|
||||
return striptags(convertLinkedinMention(convertToAscii(html)), ['ul', 'li']);
|
||||
}
|
||||
|
||||
// Strip all other tags
|
||||
return striptags(html);
|
||||
return striptags(html, ['ul', 'li']);
|
||||
};
|
||||
|
||||
export const convertLinkedinMention = (value: string) => {
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
export interface ArticleIntegrationsInterface {
|
||||
authenticate(token: string): Promise<{
|
||||
id: string;
|
||||
name: string;
|
||||
token: string;
|
||||
picture: string;
|
||||
username: string;
|
||||
}>;
|
||||
post(
|
||||
token: string,
|
||||
content: string,
|
||||
settings: object
|
||||
): Promise<{ postId: string; releaseURL: string }>;
|
||||
}
|
||||
|
||||
export interface ArticleProvider extends ArticleIntegrationsInterface {
|
||||
identifier: string;
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -1,16 +1,13 @@
|
|||
import 'reflect-metadata';
|
||||
|
||||
import {
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { XProvider } from '@gitroom/nestjs-libraries/integrations/social/x.provider';
|
||||
import { SocialProvider } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
import { LinkedinProvider } from '@gitroom/nestjs-libraries/integrations/social/linkedin.provider';
|
||||
import { RedditProvider } from '@gitroom/nestjs-libraries/integrations/social/reddit.provider';
|
||||
import { DevToProvider } from '@gitroom/nestjs-libraries/integrations/social/dev.to.provider';
|
||||
import { HashnodeProvider } from '@gitroom/nestjs-libraries/integrations/social/hashnode.provider';
|
||||
import { MediumProvider } from '@gitroom/nestjs-libraries/integrations/article/medium.provider';
|
||||
import { ArticleProvider } from '@gitroom/nestjs-libraries/integrations/article/article.integrations.interface';
|
||||
import { MediumProvider } from '@gitroom/nestjs-libraries/integrations/social/medium.provider';
|
||||
import { FacebookProvider } from '@gitroom/nestjs-libraries/integrations/social/facebook.provider';
|
||||
import { InstagramProvider } from '@gitroom/nestjs-libraries/integrations/social/instagram.provider';
|
||||
import { YoutubeProvider } from '@gitroom/nestjs-libraries/integrations/social/youtube.provider';
|
||||
|
|
@ -58,9 +55,6 @@ export const socialIntegrationList: SocialProvider[] = [
|
|||
// new MastodonCustomProvider(),
|
||||
];
|
||||
|
||||
const articleIntegrationList: ArticleProvider[] = [
|
||||
];
|
||||
|
||||
@Injectable()
|
||||
export class IntegrationManager {
|
||||
async getAllIntegrations() {
|
||||
|
|
@ -70,15 +64,13 @@ export class IntegrationManager {
|
|||
name: p.name,
|
||||
identifier: p.identifier,
|
||||
toolTip: p.toolTip,
|
||||
editor: p.editor,
|
||||
isExternal: !!p.externalUrl,
|
||||
isWeb3: !!p.isWeb3,
|
||||
...(p.customFields ? { customFields: await p.customFields() } : {}),
|
||||
}))
|
||||
),
|
||||
article: articleIntegrationList.map((p) => ({
|
||||
name: p.name,
|
||||
identifier: p.identifier,
|
||||
})),
|
||||
article: [] as any[],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -123,10 +115,4 @@ export class IntegrationManager {
|
|||
getSocialIntegration(integration: string): SocialProvider {
|
||||
return socialIntegrationList.find((i) => i.identifier === integration)!;
|
||||
}
|
||||
getAllowedArticlesIntegrations() {
|
||||
return articleIntegrationList.map((p) => p.identifier);
|
||||
}
|
||||
getArticlesIntegration(integration: string): ArticleProvider {
|
||||
return articleIntegrationList.find((i) => i.identifier === integration)!;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ export class BlueskyProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Bluesky';
|
||||
isBetweenSteps = false;
|
||||
scopes = ['write:statuses', 'profile', 'write:media'];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async customFields() {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export class DevToProvider extends SocialAbstract implements SocialProvider {
|
|||
identifier = 'devto';
|
||||
name = 'Dev.to';
|
||||
isBetweenSteps = false;
|
||||
editor = 'markdown' as const;
|
||||
scopes = [] as string[];
|
||||
|
||||
async generateAuthUrl() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider {
|
|||
identifier = 'discord';
|
||||
name = 'Discord';
|
||||
isBetweenSteps = false;
|
||||
editor = 'markdown' as const;
|
||||
scopes = ['identify', 'guilds'];
|
||||
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
||||
const { access_token, expires_in, refresh_token } = await (
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export class DribbbleProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Dribbble';
|
||||
isBetweenSteps = false;
|
||||
scopes = ['public', 'upload'];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
||||
const { access_token, expires_in } = await (
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
|||
'pages_read_engagement',
|
||||
'read_insights',
|
||||
];
|
||||
editor = 'normal' as const;
|
||||
|
||||
override handleErrors(body: string):
|
||||
| {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export class FarcasterProvider
|
|||
isBetweenSteps = false;
|
||||
isWeb3 = true;
|
||||
scopes = [] as string[];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
SocialProvider,
|
||||
} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { tags } from '@gitroom/nestjs-libraries/integrations/article/hashnode.tags';
|
||||
import { tags } from '@gitroom/nestjs-libraries/integrations/social/hashnode.tags';
|
||||
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
||||
import { HashnodeSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/hashnode.settings.dto';
|
||||
import dayjs from 'dayjs';
|
||||
|
|
@ -17,6 +17,7 @@ export class HashnodeProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Hashnode';
|
||||
isBetweenSteps = false;
|
||||
scopes = [] as string[];
|
||||
editor = 'markdown' as const;
|
||||
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import dayjs from 'dayjs';
|
|||
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { InstagramDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/instagram.dto';
|
||||
import { Integration } from '@prisma/client';
|
||||
import { number } from 'yup';
|
||||
|
||||
export class InstagramProvider
|
||||
extends SocialAbstract
|
||||
|
|
@ -30,6 +29,7 @@ export class InstagramProvider
|
|||
'instagram_manage_comments',
|
||||
'instagram_manage_insights',
|
||||
];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ export class InstagramStandaloneProvider
|
|||
'instagram_business_manage_insights',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
public override handleErrors(body: string): { type: "refresh-token" | "bad-body"; value: string } | undefined {
|
||||
return instagramProvider.handleErrors(body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export class LemmyProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Lemmy';
|
||||
isBetweenSteps = false;
|
||||
scopes = [] as string[];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async customFields() {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ export class LinkedinPageProvider
|
|||
'r_organization_social',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
override async refreshToken(
|
||||
refresh_token: string
|
||||
): Promise<AuthTokenDetails> {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider {
|
|||
'r_organization_social',
|
||||
];
|
||||
refreshWait = true;
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
|||
export class MastodonCustomProvider extends MastodonProvider {
|
||||
override identifier = 'mastodon-custom';
|
||||
override name = 'M. Instance';
|
||||
editor = 'normal' as const;
|
||||
|
||||
async externalUrl(url: string) {
|
||||
const form = new FormData();
|
||||
form.append('client_name', 'Postiz');
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export class MastodonProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Mastodon';
|
||||
isBetweenSteps = false;
|
||||
scopes = ['write:statuses', 'profile', 'write:media'];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { ArticleProvider } from '@gitroom/nestjs-libraries/integrations/article/article.integrations.interface';
|
||||
import { MediumSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/medium.settings.dto';
|
||||
import {
|
||||
AuthTokenDetails,
|
||||
PostDetails,
|
||||
|
|
@ -16,6 +14,7 @@ export class MediumProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Medium';
|
||||
isBetweenSteps = false;
|
||||
scopes = [] as string[];
|
||||
editor = 'markdown' as const;
|
||||
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
|
|
@ -27,7 +27,8 @@ export class NostrProvider extends SocialAbstract implements SocialProvider {
|
|||
identifier = 'nostr';
|
||||
name = 'Nostr';
|
||||
isBetweenSteps = false;
|
||||
scopes = [];
|
||||
scopes = [] as string[];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async customFields() {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ export class PinterestProvider
|
|||
'user_accounts:read',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
||||
const { access_token, expires_in } = await (
|
||||
await this.fetch('https://api.pinterest.com/v5/oauth/token', {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export class RedditProvider extends SocialAbstract implements SocialProvider {
|
|||
name = 'Reddit';
|
||||
isBetweenSteps = false;
|
||||
scopes = ['read', 'identity', 'submit', 'flair'];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export class SlackProvider extends SocialAbstract implements SocialProvider {
|
|||
identifier = 'slack';
|
||||
name = 'Slack';
|
||||
isBetweenSteps = false;
|
||||
editor = 'normal' as const;
|
||||
scopes = [
|
||||
'channels:read',
|
||||
'chat:write',
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ export interface SocialProvider
|
|||
refreshWait?: boolean;
|
||||
convertToJPEG?: boolean;
|
||||
isWeb3?: boolean;
|
||||
editor: 'normal' | 'markdown' | 'html';
|
||||
customFields?: () => Promise<
|
||||
{
|
||||
key: string;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider {
|
|||
isBetweenSteps = false;
|
||||
isWeb3 = true;
|
||||
scopes = [] as string[];
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ export class ThreadsProvider extends SocialAbstract implements SocialProvider {
|
|||
'threads_manage_insights',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
const { access_token } = await (
|
||||
await this.fetch(
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider {
|
|||
'user.info.profile',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
override handleErrors(body: string):
|
||||
| {
|
||||
type: 'refresh-token' | 'bad-body';
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ export class VkProvider extends SocialAbstract implements SocialProvider {
|
|||
'video',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh: string): Promise<AuthTokenDetails> {
|
||||
const [oldRefreshToken, device_id] = refresh.split('&&&&');
|
||||
const formData = new FormData();
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ export class XProvider extends SocialAbstract implements SocialProvider {
|
|||
toolTip =
|
||||
'You will be logged in into your current account, if you would like a different account, change it first on X';
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
@Plug({
|
||||
identifier: 'x-autoRepostPost',
|
||||
title: 'Auto Repost Posts',
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ export class YoutubeProvider extends SocialAbstract implements SocialProvider {
|
|||
'https://www.googleapis.com/auth/yt-analytics.readonly',
|
||||
];
|
||||
|
||||
editor = 'normal' as const;
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
const { client, oauth2 } = clientAndYoutube();
|
||||
client.setCredentials({ refresh_token });
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
"@tiptap/extension-bold": "^3.0.6",
|
||||
"@tiptap/extension-document": "^3.0.6",
|
||||
"@tiptap/extension-history": "^3.0.7",
|
||||
"@tiptap/extension-list": "^3.0.7",
|
||||
"@tiptap/extension-paragraph": "^3.0.6",
|
||||
"@tiptap/extension-text": "^3.0.6",
|
||||
"@tiptap/extension-underline": "^3.0.6",
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@ importers:
|
|||
'@tiptap/extension-history':
|
||||
specifier: ^3.0.7
|
||||
version: 3.0.7(@tiptap/extensions@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-list':
|
||||
specifier: ^3.0.7
|
||||
version: 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-paragraph':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
|
|
@ -5524,11 +5527,11 @@ packages:
|
|||
peerDependencies:
|
||||
'@tiptap/extension-list': ^3.0.6
|
||||
|
||||
'@tiptap/extension-list@3.0.6':
|
||||
resolution: {integrity: sha512-pg4R8cjUSMKuMjfOJexFt961U0UDUXfChXQh7PI7BCRCxLAtUvm2l0kGg4OMXiM1PM/ylTApdtUDal0gdOuSrQ==}
|
||||
'@tiptap/extension-list@3.0.7':
|
||||
resolution: {integrity: sha512-rwu5dXRO0YLyxndMHI17PoxK0x0ZaMZKRZflqOy8fSnXNwd3Tdy8/6a9tsmpgO38kOZEYuvMVaeB7J/+UeBVLg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^3.0.6
|
||||
'@tiptap/pm': ^3.0.6
|
||||
'@tiptap/core': ^3.0.7
|
||||
'@tiptap/pm': ^3.0.7
|
||||
|
||||
'@tiptap/extension-ordered-list@3.0.6':
|
||||
resolution: {integrity: sha512-9SbeGO6kGKoX8GwhaSgpFNCGxlzfGu5otK5DE+Unn5F8/gIYGBJkXTZE1tj8XzPmH6lWhmKJQPudANnW6yuKqg==}
|
||||
|
|
@ -21155,9 +21158,9 @@ snapshots:
|
|||
'@tiptap/pm': 3.0.6
|
||||
optional: true
|
||||
|
||||
'@tiptap/extension-bullet-list@3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
'@tiptap/extension-bullet-list@3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
|
||||
'@tiptap/extension-code-block@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)':
|
||||
dependencies:
|
||||
|
|
@ -21214,22 +21217,22 @@ snapshots:
|
|||
'@tiptap/pm': 3.0.6
|
||||
linkifyjs: 4.3.1
|
||||
|
||||
'@tiptap/extension-list-item@3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
'@tiptap/extension-list-item@3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
|
||||
'@tiptap/extension-list-keymap@3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
'@tiptap/extension-list-keymap@3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
|
||||
'@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)':
|
||||
'@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.0.6(@tiptap/pm@3.0.6)
|
||||
'@tiptap/pm': 3.0.6
|
||||
|
||||
'@tiptap/extension-ordered-list@3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
'@tiptap/extension-ordered-list@3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
|
||||
'@tiptap/extension-paragraph@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))':
|
||||
dependencies:
|
||||
|
|
@ -21293,7 +21296,7 @@ snapshots:
|
|||
'@tiptap/core': 3.0.6(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-blockquote': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-bold': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-bullet-list': 3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-bullet-list': 3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-code': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-code-block': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-document': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
|
|
@ -21304,10 +21307,10 @@ snapshots:
|
|||
'@tiptap/extension-horizontal-rule': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-italic': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-link': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list-item': 3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-list-keymap': 3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-ordered-list': 3.0.6(@tiptap/extension-list@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-list': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)
|
||||
'@tiptap/extension-list-item': 3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-list-keymap': 3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-ordered-list': 3.0.6(@tiptap/extension-list@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-paragraph': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-strike': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
'@tiptap/extension-text': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))
|
||||
|
|
|
|||
Loading…
Reference in New Issue