Skip to content

Commit 08e4d0a

Browse files
committed
Merge branch 'main' into room-resource-skills
2 parents 3d257b9 + b22fd7a commit 08e4d0a

File tree

11 files changed

+368
-37
lines changed

11 files changed

+368
-37
lines changed

packages/base/code-ref.gts

+76-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type Owner from '@ember/owner';
2+
import { tracked } from '@glimmer/tracking';
13
import {
24
Component,
35
primitive,
@@ -13,7 +15,14 @@ import {
1315
type SerializeOpts,
1416
type JSONAPISingleResourceDocument,
1517
} from './card-api';
16-
import { ResolvedCodeRef } from '@cardstack/runtime-common';
18+
import { restartableTask } from 'ember-concurrency';
19+
import { consume } from 'ember-provide-consume-context';
20+
import {
21+
type ResolvedCodeRef,
22+
CardURLContextName,
23+
} from '@cardstack/runtime-common';
24+
import { not } from '@cardstack/boxel-ui/helpers';
25+
import { BoxelInput } from '@cardstack/boxel-ui/components';
1726
import CodeIcon from '@cardstack/boxel-icons/code';
1827

1928
function moduleIsUrlLike(module: string) {
@@ -35,6 +44,70 @@ class BaseView extends Component<typeof CodeRefField> {
3544
</template>
3645
}
3746

47+
class EditView extends Component<typeof CodeRefField> {
48+
@consume(CardURLContextName) declare cardURL: string | undefined;
49+
@tracked validationState: 'initial' | 'valid' | 'invalid' = 'initial';
50+
@tracked private maybeCodeRef: string | undefined = maybeSerializeCodeRef(
51+
this.args.model ?? undefined,
52+
);
53+
54+
<template>
55+
<BoxelInput
56+
data-test-hasValidated={{this.setIfValid.isIdle}}
57+
@value={{this.maybeCodeRef}}
58+
@state={{this.validationState}}
59+
@onInput={{this.onInput}}
60+
@disabled={{not @canEdit}}
61+
/>
62+
</template>
63+
64+
constructor(owner: Owner, args: any) {
65+
super(owner, args);
66+
if (this.maybeCodeRef != null) {
67+
this.setIfValid.perform(this.maybeCodeRef, { checkOnly: true });
68+
}
69+
}
70+
71+
private onInput = (inputVal: string) => {
72+
this.maybeCodeRef = inputVal;
73+
this.setIfValid.perform(this.maybeCodeRef);
74+
};
75+
76+
private setIfValid = restartableTask(
77+
async (maybeCodeRef: string, opts?: { checkOnly?: true }) => {
78+
this.validationState = 'initial';
79+
if (maybeCodeRef.length === 0) {
80+
if (!opts?.checkOnly) {
81+
this.args.set(undefined);
82+
}
83+
return;
84+
}
85+
86+
let parts = maybeCodeRef.split('/');
87+
if (parts.length < 2) {
88+
this.validationState = 'invalid';
89+
return;
90+
}
91+
92+
let name = parts.pop()!;
93+
let module = parts.join('/');
94+
try {
95+
let code = (await import(module))[name];
96+
if (code) {
97+
this.validationState = 'valid';
98+
if (!opts?.checkOnly) {
99+
this.args.set({ module, name });
100+
}
101+
} else {
102+
this.validationState = 'invalid';
103+
}
104+
} catch (err) {
105+
this.validationState = 'invalid';
106+
}
107+
},
108+
);
109+
}
110+
38111
export default class CodeRefField extends FieldDef {
39112
static icon = CodeIcon;
40113
static [primitive]: ResolvedCodeRef;
@@ -71,8 +144,8 @@ export default class CodeRefField extends FieldDef {
71144
}
72145

73146
static embedded = class Embedded extends BaseView {};
74-
// The edit template is meant to be read-only, this field card is not mutable
75-
static edit = class Edit extends BaseView {};
147+
148+
static edit = EditView;
76149
}
77150

78151
function maybeSerializeCodeRef(

packages/host/app/components/ai-assistant/formatted-message.gts

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default class FormattedMessage extends Component<FormattedMessageSignatur
112112
:deep(.code-copy-button .copy-text) {
113113
color: transparent;
114114
}
115-
:deep(.code-copy-button .copy-text:hover) {
115+
:deep(.code-copy-button:hover .copy-text) {
116116
color: var(--boxel-highlight);
117117
}
118118
</style>

packages/host/app/components/ai-assistant/message/index.gts

+8-6
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export default class AiAssistantMessage extends Component<Signature> {
261261
{{/if}}
262262

263263
{{#if @resources.errors.length}}
264-
<div class='error-container'>
264+
<div class='error-container error-footer'>
265265
{{#each @resources.errors as |resourceError|}}
266266
<FailureBordered class='error-icon' />
267267
<div class='error-message' data-test-card-error>
@@ -348,12 +348,7 @@ export default class AiAssistantMessage extends Component<Signature> {
348348
padding: var(--ai-assistant-message-padding, var(--boxel-sp));
349349
}
350350
351-
.is-from-assistant .content :deep(.message) {
352-
padding: var(--ai-assistant-message-padding, var(--boxel-sp));
353-
}
354-
355351
.is-from-assistant .content {
356-
padding: 0;
357352
background-color: var(--ai-bot-message-background-color);
358353
color: var(--boxel-light);
359354
/* the below font-smoothing options are only recommended for light-colored
@@ -422,6 +417,13 @@ export default class AiAssistantMessage extends Component<Signature> {
422417
font: 600 var(--boxel-font-sm);
423418
letter-spacing: var(--boxel-lsp);
424419
}
420+
.error-footer {
421+
--fill-container-spacing: calc(
422+
-1 * var(--ai-assistant-message-padding)
423+
);
424+
margin-inline: var(--fill-container-spacing);
425+
margin-bottom: var(--fill-container-spacing);
426+
}
425427
.error-icon {
426428
--icon-background-color: var(--boxel-light);
427429
--icon-color: var(--boxel-danger);

packages/host/app/components/matrix/room-message-command.gts

+23-6
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export default class RoomMessageCommand extends Component<Signature> {
198198
{{#if @isDisplayingCode}}
199199
<div class='preview-code'>
200200
<Button
201-
class='copy-to-clipboard-button'
201+
class='code-copy-button'
202202
@kind='text-only'
203203
@size='extra-small'
204204
{{on 'click' this.copyToClipboard}}
@@ -210,7 +210,7 @@ export default class RoomMessageCommand extends Component<Signature> {
210210
role='presentation'
211211
aria-hidden='true'
212212
/>
213-
Copy to clipboard
213+
<span class='copy-text'>Copy to clipboard</span>
214214
</Button>
215215
<div
216216
class='monaco-container'
@@ -279,7 +279,17 @@ export default class RoomMessageCommand extends Component<Signature> {
279279
.command-result-card-preview {
280280
margin-top: var(--boxel-sp);
281281
}
282-
.copy-to-clipboard-button {
282+
.preview-code {
283+
--spacing: var(--boxel-sp-sm);
284+
--fill-container-spacing: calc(
285+
-1 * var(--ai-assistant-message-padding)
286+
);
287+
margin: var(--boxel-sp) var(--fill-container-spacing)
288+
var(--fill-container-spacing) var(--fill-container-spacing);
289+
padding: var(--spacing) 0;
290+
background-color: var(--boxel-dark);
291+
}
292+
.code-copy-button {
283293
--boxel-button-font: 600 var(--boxel-font-xs);
284294
--boxel-button-padding: 0 var(--boxel-sp-xs);
285295
--icon-color: var(--boxel-highlight);
@@ -290,9 +300,16 @@ export default class RoomMessageCommand extends Component<Signature> {
290300
grid-template-columns: auto 1fr;
291301
gap: var(--spacing);
292302
}
293-
.copy-to-clipboard-button:hover:not(:disabled) {
294-
--boxel-button-text-color: var(--boxel-highlight);
295-
filter: brightness(1.1);
303+
.code-copy-button > .copy-text {
304+
color: transparent;
305+
}
306+
.code-copy-button:hover:not(:disabled) > .copy-text {
307+
color: var(--boxel-highlight);
308+
}
309+
.monaco-container {
310+
height: var(--monaco-container-height);
311+
min-height: 10rem;
312+
max-height: 30vh;
296313
}
297314
.header {
298315
--boxel-label-color: var(--boxel-450);

packages/host/app/components/preview.gts

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { provide } from 'ember-provide-consume-context';
55
import {
66
CardContextName,
77
DefaultFormatsContextName,
8+
CardURLContextName,
89
ResolvedCodeRef,
910
} from '@cardstack/runtime-common';
1011

@@ -46,6 +47,14 @@ export default class Preview extends Component<Signature> {
4647
};
4748
}
4849

50+
@provide(CardURLContextName)
51+
// @ts-ignore "cardURL is declared but not used"
52+
private get cardURL() {
53+
return 'id' in this.args.card
54+
? (this.args.card?.id as string | undefined)
55+
: undefined;
56+
}
57+
4958
<template>
5059
<this.renderedCard @displayContainer={{@displayContainer}} ...attributes />
5160
</template>

packages/host/tests/integration/components/ai-assistant-panel-test.gts

+3
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ module('Integration | ai-assistant-panel', function (hooks) {
621621
'it can preview code when a change is proposed',
622622
);
623623
assert.dom('[data-test-copy-code]').isEnabled('copy button is available');
624+
await percySnapshot(assert);
624625

625626
await click('[data-test-view-code-button]');
626627
assert.dom('[data-test-code-editor]').doesNotExist();
@@ -2816,5 +2817,7 @@ module('Integration | ai-assistant-panel', function (hooks) {
28162817
`console.log("hello world");`,
28172818
'monaco content is correct',
28182819
);
2820+
2821+
await percySnapshot(assert);
28192822
});
28202823
});

0 commit comments

Comments
 (0)