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

Feature: AI Node and AI Actions extension #26055

Merged
merged 62 commits into from Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
8909420
Created AI content node
Jul 27, 2023
e9fdb40
Merge branch 'master' into new-extension-user-input-chatgpt
Jul 27, 2023
4cc7f6a
Created ai-content-service
Aug 2, 2023
b1ddbb7
Created AI prompt content extension
Aug 2, 2023
13c2932
Merge branch 'master' into new-extension-user-input-chatgpt
Aug 2, 2023
ea9977f
Update ai-content.service.ts
Aug 3, 2023
da83c59
Optimised and aligned extension code
Aug 3, 2023
b7893bb
Resolved comments on PR
Aug 4, 2023
91338b6
Removed ai content node file
Aug 4, 2023
bceda9b
Update ai-content.service.ts
Aug 4, 2023
8116d58
Remove import path for ai-content-node
Aug 4, 2023
ac18c95
Updated the ai-prompt form
Aug 4, 2023
4156879
align ai text prompt extension
Aug 7, 2023
db3efe5
Resovled comments on pull
Aug 8, 2023
52e9666
Fix the aiTextPrompt form
Aug 8, 2023
70f8297
Updated extension related code
Aug 8, 2023
77c70b6
Update ai-content-prompt.plugin.ts
Aug 8, 2023
3c79581
Remove some extra code
Aug 8, 2023
46a61a8
Fixed outside click for aiContentPrompt extension
nikolaPhy Aug 9, 2023
b42a2c3
Created ai content node
nikolaPhy Aug 9, 2023
155773d
Updated ai-content node
nikolaPhy Aug 10, 2023
02b292b
Remove unused code, resolve comments on PR
nikolaPhy Aug 14, 2023
2c832e9
Merge branch 'master' into new-extension-user-input-chatgpt
nikolaPhy Aug 14, 2023
ef90d31
ai-content-prompt extension code optimisation
nikolaPhy Aug 14, 2023
b6a937f
Update ai-content-prompt.plugin.ts
nikolaPhy Aug 14, 2023
f05105e
Integrated with AI api
nikolaPhy Aug 21, 2023
bc86f8f
Merge branch 'master' into new-extension-user-input-chatgpt
nikolaPhy Aug 21, 2023
55a0b18
Merge branch 'new-extension-user-input-chatgpt' into feature/ai-conte…
nikolaPhy Aug 21, 2023
9d5f721
insert ai node on response
nikolaPhy Aug 21, 2023
8cab5ca
textPrompt extension code optimsation
nikolaPhy Aug 21, 2023
772a0fc
Update ai-content.service.ts
nikolaPhy Aug 22, 2023
c41b9d9
Resolve comments on pull req
nikolaPhy Aug 23, 2023
60e7337
handle close extension on outside click and content flip fix
nikolaPhy Aug 24, 2023
60f81dd
Added focus field method and type for form
nikolaPhy Aug 24, 2023
94c6590
Merge branch 'master' into new-extension-user-input-chatgpt
nikolaPhy Aug 25, 2023
69a4e02
Merge branch 'new-extension-user-input-chatgpt' into feature/ai-conte…
nikolaPhy Aug 25, 2023
b62772e
Change name of ai node creation command
nikolaPhy Aug 25, 2023
aa15c03
Update the ai-content icon in the actions menu list
nikolaPhy Aug 25, 2023
ff7f3df
Update ai-content-prompt.component.scss
nikolaPhy Aug 28, 2023
e18759a
Resolved comments on pull
nikolaPhy Aug 28, 2023
18039c7
Merge branch 'new-extension-user-input-chatgpt' into feature/ai-conte…
nikolaPhy Aug 29, 2023
921e046
Added pening status and update the name of destroy var
nikolaPhy Sep 1, 2023
6548c71
Merge branch 'master' into new-extension-user-input-chatgpt
nikolaPhy Sep 1, 2023
0ace3d7
Merge branch 'new-extension-user-input-chatgpt' into feature/ai-conte…
nikolaPhy Sep 1, 2023
daac750
Implement ai-content-actions extension
Sep 5, 2023
2d684d6
ai-prompt extension code optimisation
Sep 6, 2023
b62bd26
Merge branch 'master' into new-extension-user-input-chatgpt
Sep 6, 2023
9a22cf7
Merge branch 'new-extension-user-input-chatgpt' into feature-ai-node-…
Sep 6, 2023
23c2352
ai-text-prompt block optimisation
Sep 11, 2023
a813fda
Merge branch 'master' into feature-ai-node-and-ai-actions
Sep 12, 2023
7080f85
Merge branch 'master' into feature-ai-node-and-ai-actions
Sep 12, 2023
3d54ccb
Update main.ts
Sep 12, 2023
31040f9
Resolve comments on pull
Sep 15, 2023
873e577
Merge branch 'master' into feature-ai-node-and-ai-actions
Oct 2, 2023
11db56b
Resolve comments on PR
Oct 6, 2023
9d6fc34
Merge branch 'master' into feature-ai-node-and-ai-actions
Oct 6, 2023
cb1b706
Code optimisation for ai-content-actions extension
Oct 6, 2023
2a33515
Fix css for p-listbox
Oct 6, 2023
663bec8
Merge branch 'master' into feature-ai-node-and-ai-actions
Oct 6, 2023
679ae0e
Merge branch 'master' into feature-ai-node-and-ai-actions
Oct 10, 2023
fd1f7a3
Merge branch 'master' into feature-ai-node-and-ai-actions
fmontes Oct 17, 2023
cfbd93b
Merge branch 'master' into feature-ai-node-and-ai-actions
wezell Oct 17, 2023
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
7 changes: 5 additions & 2 deletions core-web/libs/block-editor/src/lib/block-editor.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DotBlockEditorComponent } from './components/dot-block-editor/dot-block
import { DotEditorCountBarComponent } from './components/dot-editor-count-bar/dot-editor-count-bar.component';
import {
AIContentPromptComponent,
AIContentActionsComponent,
BubbleLinkFormComponent,
BubbleMenuButtonComponent,
BubbleMenuComponent,
Expand Down Expand Up @@ -52,7 +53,8 @@ import { SharedModule } from './shared/shared.module';
DotBlockEditorComponent,
DotEditorCountBarComponent,
FloatingButtonComponent,
AIContentPromptComponent
AIContentPromptComponent,
AIContentActionsComponent
],
providers: [DotUploadFileService, LoggerService, StringUtils, AiContentService],
exports: [
Expand All @@ -63,7 +65,8 @@ import { SharedModule } from './shared/shared.module';
SharedModule,
BubbleFormComponent,
DotBlockEditorComponent,
AIContentPromptComponent
AIContentPromptComponent,
AIContentActionsComponent
]
})
export class BlockEditorModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@
}
}
}

.ai-content-container {
&.ProseMirror-selectednode {
background-color: $color-palette-primary-op-20;
border: 1px solid $color-palette-primary-300;
}
}
}

tiptap-editor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ import {
FREEZE_SCROLL_KEY,
AssetUploader,
DotComands,
AIContentPromptExtension
AIContentPromptExtension,
AIContentActionsExtension
} from '../../extensions';
import { DotPlaceholder } from '../../extensions/dot-placeholder/dot-placeholder-plugin';
import { ContentletBlock, ImageNode, VideoNode } from '../../nodes';
import { ContentletBlock, ImageNode, VideoNode, AIContentNode } from '../../nodes';
import {
formatHTML,
removeInvalidNodes,
Expand Down Expand Up @@ -109,7 +110,8 @@ export class DotBlockEditorComponent implements OnInit, OnDestroy {
['dotContent', ContentletBlock(this.injector)],
['image', ImageNode],
['video', VideoNode],
['table', DotTableExtension()]
['table', DotTableExtension()],
['aiContent', AIContentNode]
]);

private destroy$: Subject<boolean> = new Subject<boolean>();
Expand Down Expand Up @@ -381,6 +383,7 @@ export class DotBlockEditorComponent implements OnInit, OnDestroy {
DotBubbleMenuExtension(this.viewContainerRef),
BubbleFormExtension(this.viewContainerRef),
AIContentPromptExtension(this.viewContainerRef),
AIContentActionsExtension(this.viewContainerRef),
DotFloatingButton(this.injector, this.viewContainerRef),
DotTableCellExtension(this.viewContainerRef),
BubbleAssetFormExtension(this.viewContainerRef),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ function execCommand({
subscript: () => editor.chain().setSubscript().focus().run(),
superscript: () => editor.chain().setSuperscript().focus().run(),
video: () => editor.commands.openAssetForm({ type: 'video' }),
aiContentPrompt: () => editor.commands.openAIPrompt()
aiContentPrompt: () => editor.commands.openAIPrompt(),
aiContent: () => editor.commands.insertAINode()
};

getCustomActions(customBlocks).forEach((option) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p-listbox [options]="actionOptions" (onClick)="$event.value.callback()">
<ng-template let-actionOption pTemplate="item">
<div class="action-content">
<i [class]="actionOption.icon"></i>
{{ actionOption.label }}
</div>
</ng-template>
</p-listbox>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@use "variables" as *;

:host ::ng-deep {
.p-listbox {
display: block;
width: 12.5rem;
padding: $spacing-1;
margin-left: $spacing-8;

li {
padding: $spacing-2 $spacing-3;

// accept option
&:first-child {
background-color: $color-palette-primary-200;
}

// regenerate option
&:nth-child(2) {
padding: $spacing-3;
background-color: $white !important;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe @fmontes can help you get rid of this !important;

}

// delete option
&:last-child {
border-top: 1px solid $color-palette-gray-300;
background-color: $white !important;
}

&:hover {
background-color: $color-palette-primary-100;
}
}
}
}

.action-content {
display: flex;
align-items: center;
color: $black;

// list option icon
i {
margin-right: $spacing-0;
color: $color-palette-gray-600;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';

import { AIContentActionsComponent } from './ai-content-actions.component';

import { AiContentService } from '../../shared';

describe('AIContentActionsComponent', () => {
let component: AIContentActionsComponent;
let fixture: ComponentFixture<AIContentActionsComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ReactiveFormsModule, HttpClientTestingModule],
declarations: [AIContentActionsComponent],
providers: [AiContentService]
}).compileComponents();

fixture = TestBed.createComponent(AIContentActionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Observable, of } from 'rxjs';

import { Component, EventEmitter, Output, OnInit } from '@angular/core';

import { AiContentService } from '../../shared/services/ai-content/ai-content.service';

interface ActionOption {
label: string;
icon: string;
selectedOption: boolean;
callback: () => void;
}

export enum ACTIONS {
ACCEPT = 'ACCEPT',
DELETE = 'DELETE',
REGENERATE = 'REGENERATE'
}

@Component({
selector: 'dot-ai-content-actions',
templateUrl: './ai-content-actions.component.html',
styleUrls: ['./ai-content-actions.component.scss']
})
export class AIContentActionsComponent implements OnInit {
@Output() actionEmitter = new EventEmitter<ACTIONS>();

actionOptions!: ActionOption[];

constructor(private aiContentService: AiContentService) {}

ngOnInit() {
this.actionOptions = [
{
label: 'Accept',
rjvelazco marked this conversation as resolved.
Show resolved Hide resolved
icon: 'pi pi-check',
callback: () => this.emitAction(ACTIONS.ACCEPT),
selectedOption: true
},
{
label: 'Regenerate',
icon: 'pi pi-sync',
callback: () => this.emitAction(ACTIONS.REGENERATE),
selectedOption: false
},
{
label: 'Delete',
icon: 'pi pi-trash',
callback: () => this.emitAction(ACTIONS.DELETE),
selectedOption: false
}
];
}

private emitAction(action: ACTIONS) {
this.actionEmitter.emit(action);
}

getLatestContent() {
return this.aiContentService.getLastContentResponse();
}

getNewContent(): Observable<string> {
const promptToUse: string = this.aiContentService.getLastUsedPrompt();

if (promptToUse) {
return this.aiContentService.getIAContent(promptToUse);
}

return of('');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { PluginKey } from 'prosemirror-state';
import { Props } from 'tippy.js';

import { ViewContainerRef } from '@angular/core';

import { Extension } from '@tiptap/core';

import { AIContentActionsComponent } from './ai-content-actions.component';
import { aiContentActionsPlugin } from './plugins/ai-content-actions.plugin';

export interface AIContentActionsOptions {
pluginKey: PluginKey;
tippyOptions?: Partial<Props>;
element: HTMLElement | null;
}

declare module '@tiptap/core' {
interface Commands<ReturnType> {
AIContentActions: {
openAIContentActions: () => ReturnType;
closeAIContentActions: () => ReturnType;
};
}
}

export const AI_CONTENT_ACTIONS_PLUGIN_KEY = new PluginKey('aiContentActions-form');

export const AIContentActionsExtension = (viewContainerRef: ViewContainerRef) => {
return Extension.create<AIContentActionsOptions>({
name: 'aiContentActions',

addOptions() {
return {
element: null,
tippyOptions: {},
pluginKey: AI_CONTENT_ACTIONS_PLUGIN_KEY
};
},

addCommands() {
return {
openAIContentActions:
() =>
({ chain }) => {
return chain()
.command(({ tr }) => {
tr.setMeta(AI_CONTENT_ACTIONS_PLUGIN_KEY, { open: true });

return true;
})
.freezeScroll(true)
.run();
},
closeAIContentActions:
() =>
({ chain }) => {
return chain()
.command(({ tr }) => {
tr.setMeta(AI_CONTENT_ACTIONS_PLUGIN_KEY, { open: false });

return true;
})
.freezeScroll(false)
.run();
}
};
},

addProseMirrorPlugins() {
const component = viewContainerRef.createComponent(AIContentActionsComponent);
component.changeDetectorRef.detectChanges();

return [
aiContentActionsPlugin({
pluginKey: this.options.pluginKey,
editor: this.editor,
element: component.location.nativeElement,
tippyOptions: this.options.tippyOptions,
component: component
})
];
}
});
};
Loading
Loading