1
+ import type Owner from ' @ember/owner' ;
2
+ import { tracked } from ' @glimmer/tracking' ;
1
3
import {
2
4
Component ,
3
5
primitive ,
@@ -13,7 +15,14 @@ import {
13
15
type SerializeOpts ,
14
16
type JSONAPISingleResourceDocument ,
15
17
} 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' ;
17
26
import CodeIcon from ' @cardstack/boxel-icons/code' ;
18
27
19
28
function moduleIsUrlLike(module : string ) {
@@ -35,6 +44,70 @@ class BaseView extends Component<typeof CodeRefField> {
35
44
</template >
36
45
}
37
46
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
+
38
111
export default class CodeRefField extends FieldDef {
39
112
static icon = CodeIcon ;
40
113
static [primitive ]: ResolvedCodeRef ;
@@ -71,8 +144,8 @@ export default class CodeRefField extends FieldDef {
71
144
}
72
145
73
146
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 ;
76
149
}
77
150
78
151
function maybeSerializeCodeRef(
0 commit comments