@cardstack/boxel-cli 0.3.0-unstable.13 → 0.3.0-unstable.58
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/bundled-types/base/card-serialization.d.ts +1 -1
- package/bundled-types/boxel-ui/icons.gts +0 -3
- package/bundled-types/host-app/commands/create-submission-workflow.ts +2 -2
- package/bundled-types/host-app/commands/get-available-realm-identifiers.ts +1 -1
- package/bundled-types/host-app/commands/get-catalog-realm-identifiers.ts +1 -1
- package/bundled-types/host-app/commands/search-cards.ts +1 -1
- package/bundled-types/host-app/components/card-catalog/modal.gts +3 -3
- package/bundled-types/host-app/components/card-search/panel.gts +1 -1
- package/bundled-types/host-app/components/card-search/search-content.gts +2 -2
- package/bundled-types/host-app/components/operator-mode/code-submode/format-chooser.gts +12 -9
- package/bundled-types/host-app/components/operator-mode/code-submode/module-inspector.gts +1 -1
- package/bundled-types/host-app/components/operator-mode/code-submode/playground/playground-panel.gts +3 -3
- package/bundled-types/host-app/components/operator-mode/create-file-modal.gts +2 -2
- package/bundled-types/host-app/components/operator-mode/workspace-chooser/index.gts +32 -24
- package/bundled-types/host-app/components/operator-mode/workspace-chooser/workspace.gts +36 -23
- package/bundled-types/host-app/components/realm-picker/index.gts +2 -2
- package/bundled-types/host-app/components/search-sheet/index.gts +1 -1
- package/bundled-types/host-app/components/with-known-realms-loaded.gts +1 -1
- package/bundled-types/host-app/services/host-mode-service.ts +21 -2
- package/bundled-types/host-app/services/matrix-service.ts +9 -8
- package/bundled-types/host-app/services/operator-mode-state-service.ts +8 -6
- package/bundled-types/host-app/services/realm-server.ts +18 -16
- package/bundled-types/host-app/services/store.ts +1 -1
- package/bundled-types/host-app/utils/card-search/url.ts +6 -2
- package/bundled-types/host-tests/helpers/index.gts +2 -2
- package/dist/index.js +68 -68
- package/package.json +1 -1
- package/src/commands/realm/publish.ts +10 -1
- package/src/commands/realm/unpublish.ts +2 -3
- package/src/lib/describe-fetch-error.ts +25 -0
|
@@ -27,7 +27,7 @@ export interface SerializeOpts {
|
|
|
27
27
|
useAbsoluteURL?: boolean;
|
|
28
28
|
omitFields?: [typeof BaseDef];
|
|
29
29
|
omitQueryFields?: boolean;
|
|
30
|
-
|
|
30
|
+
maybeRelativeReference?: (possibleReference: string) => string;
|
|
31
31
|
overrides?: Map<string, typeof BaseDef>;
|
|
32
32
|
}
|
|
33
33
|
export interface DeserializeOpts {
|
|
@@ -66,7 +66,6 @@ import ImagePlaceholder from './icons/image-placeholder.gts';
|
|
|
66
66
|
import Isolated from './icons/isolated.gts';
|
|
67
67
|
import LoadingIndicator from './icons/loading-indicator.gts';
|
|
68
68
|
import Lock from './icons/lock.gts';
|
|
69
|
-
import Markdown from './icons/markdown.gts';
|
|
70
69
|
import Profile from './icons/profile.gts';
|
|
71
70
|
import PublishSiteIcon from './icons/publish-site-icon.gts';
|
|
72
71
|
import Rows4 from './icons/rows-4.gts';
|
|
@@ -147,7 +146,6 @@ export const ALL_ICON_COMPONENTS = [
|
|
|
147
146
|
Isolated,
|
|
148
147
|
LoadingIndicator,
|
|
149
148
|
Lock,
|
|
150
|
-
Markdown,
|
|
151
149
|
Profile,
|
|
152
150
|
PublishSiteIcon,
|
|
153
151
|
Rows4,
|
|
@@ -230,7 +228,6 @@ export {
|
|
|
230
228
|
Isolated,
|
|
231
229
|
LoadingIndicator,
|
|
232
230
|
Lock,
|
|
233
|
-
Markdown,
|
|
234
231
|
Profile,
|
|
235
232
|
PublishSiteIcon,
|
|
236
233
|
Rows4,
|
|
@@ -37,7 +37,7 @@ export default class CreateSubmissionWorkflowCommand extends HostBaseCommand<
|
|
|
37
37
|
requireInputFields = ['realm', 'listingId'];
|
|
38
38
|
|
|
39
39
|
get submissionsRealm(): string | undefined {
|
|
40
|
-
return this.realmServer.
|
|
40
|
+
return this.realmServer.catalogRealmIdentifiers.find((realm) =>
|
|
41
41
|
realm.endsWith('/submissions/'),
|
|
42
42
|
);
|
|
43
43
|
}
|
|
@@ -165,7 +165,7 @@ export default class CreateSubmissionWorkflowCommand extends HostBaseCommand<
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
private get catalogRealm(): string | undefined {
|
|
168
|
-
return this.realmServer.
|
|
168
|
+
return this.realmServer.catalogRealmIdentifiers.find((realm) =>
|
|
169
169
|
realm.endsWith('/catalog/'),
|
|
170
170
|
);
|
|
171
171
|
}
|
|
@@ -23,7 +23,7 @@ export default class GetAvailableRealmIdentifiersCommand extends HostBaseCommand
|
|
|
23
23
|
let commandModule = await this.loadCommandModule();
|
|
24
24
|
const { GetAvailableRealmIdentifiersResult } = commandModule;
|
|
25
25
|
return new GetAvailableRealmIdentifiersResult({
|
|
26
|
-
realmIdentifiers: this.realmServer.
|
|
26
|
+
realmIdentifiers: this.realmServer.availableRealmIdentifiers,
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -23,7 +23,7 @@ export default class GetCatalogRealmIdentifiersCommand extends HostBaseCommand<
|
|
|
23
23
|
let commandModule = await this.loadCommandModule();
|
|
24
24
|
const { GetCatalogRealmIdentifiersResult } = commandModule;
|
|
25
25
|
return new GetCatalogRealmIdentifiersResult({
|
|
26
|
-
realmIdentifiers: this.realmServer.
|
|
26
|
+
realmIdentifiers: this.realmServer.catalogRealmIdentifiers,
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -75,7 +75,7 @@ export class SearchCardsByQueryCommand extends HostBaseCommand<
|
|
|
75
75
|
input: BaseCommandModule.SearchCardsByQueryInput,
|
|
76
76
|
): Promise<BaseCommandModule.SearchCardsResult> {
|
|
77
77
|
assertQuery(input.query);
|
|
78
|
-
let realmUrls = this.realmServer.
|
|
78
|
+
let realmUrls = this.realmServer.availableRealmIdentifiers;
|
|
79
79
|
let instances: CardDef[] = [];
|
|
80
80
|
try {
|
|
81
81
|
instances = await this.store.search(input.query, realmUrls);
|
|
@@ -344,7 +344,7 @@ export default class CardCatalogModal extends Component<Signature> {
|
|
|
344
344
|
await this.realmServer.ready;
|
|
345
345
|
// Preload realm info without blocking the modal from opening.
|
|
346
346
|
let prefetchRealmInfo = Promise.all(
|
|
347
|
-
this.realmServer.
|
|
347
|
+
this.realmServer.availableRealmIdentifiers.map(async (realmURL) => {
|
|
348
348
|
let resource = this.realm.getOrCreateRealmResource(realmURL);
|
|
349
349
|
try {
|
|
350
350
|
await resource.fetchInfo();
|
|
@@ -378,7 +378,7 @@ export default class CardCatalogModal extends Component<Signature> {
|
|
|
378
378
|
if (opts?.preselectedCardTypeQuery) {
|
|
379
379
|
let instances: CardDef[] = await this.store.search(
|
|
380
380
|
opts.preselectedCardTypeQuery!,
|
|
381
|
-
this.realmServer.
|
|
381
|
+
this.realmServer.availableRealmIdentifiers,
|
|
382
382
|
);
|
|
383
383
|
if (instances?.[0]?.id) {
|
|
384
384
|
preselectedCardUrl = `${instances[0].id}.json`;
|
|
@@ -399,7 +399,7 @@ export default class CardCatalogModal extends Component<Signature> {
|
|
|
399
399
|
searchKey: '',
|
|
400
400
|
dismissModal: false,
|
|
401
401
|
baseFilter: query.filter,
|
|
402
|
-
availableRealmUrls: this.realmServer.
|
|
402
|
+
availableRealmUrls: this.realmServer.availableRealmIdentifiers,
|
|
403
403
|
selectedCards: preselectedCardUrls,
|
|
404
404
|
multiSelect: opts?.multiSelect ?? false,
|
|
405
405
|
hasPreselectedCard: preselectedCardUrls.length > 0,
|
|
@@ -66,7 +66,7 @@ export default class SearchPanel extends Component<Signature> {
|
|
|
66
66
|
|
|
67
67
|
private get selectedRealmURLs(): string[] {
|
|
68
68
|
if (this.selectedRealms.length === 0) {
|
|
69
|
-
return this.realmServer.
|
|
69
|
+
return this.realmServer.availableRealmIdentifiers;
|
|
70
70
|
}
|
|
71
71
|
return this.selectedRealms.map((url) => url.href);
|
|
72
72
|
}
|
|
@@ -167,7 +167,7 @@ export default class SearchContent extends Component<Signature> {
|
|
|
167
167
|
private get searchKeyAsURL() {
|
|
168
168
|
return resolveSearchKeyAsURL(
|
|
169
169
|
this.args.searchKey,
|
|
170
|
-
this.realmServer.
|
|
170
|
+
this.realmServer.availableRealmIdentifiers,
|
|
171
171
|
);
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -328,7 +328,7 @@ export default class SearchContent extends Component<Signature> {
|
|
|
328
328
|
const urls =
|
|
329
329
|
this.args.realmFilter.selectedURLs.length > 0
|
|
330
330
|
? this.args.realmFilter.selectedURLs
|
|
331
|
-
: this.realmServer.
|
|
331
|
+
: this.realmServer.availableRealmIdentifiers;
|
|
332
332
|
return urls ?? [];
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -7,6 +7,7 @@ import Component from '@glimmer/component';
|
|
|
7
7
|
import { tracked } from '@glimmer/tracking';
|
|
8
8
|
|
|
9
9
|
import MetadataIcon from '@cardstack/boxel-icons/clipboard-data';
|
|
10
|
+
import MarkdownIcon from '@cardstack/boxel-icons/markdown';
|
|
10
11
|
import EditIcon from '@cardstack/boxel-icons/pencil';
|
|
11
12
|
import { modifier } from 'ember-modifier';
|
|
12
13
|
import window from 'ember-window-mock';
|
|
@@ -19,7 +20,6 @@ import {
|
|
|
19
20
|
Fitted as FittedIcon,
|
|
20
21
|
Atom as AtomIcon,
|
|
21
22
|
Head as HeadIcon,
|
|
22
|
-
Markdown as MarkdownIcon,
|
|
23
23
|
Form as FormIcon,
|
|
24
24
|
type Icon,
|
|
25
25
|
} from '@cardstack/boxel-ui/icons';
|
|
@@ -86,7 +86,12 @@ const FormatButton: TemplateOnlyComponent<FormatButtonSignature> = <template>
|
|
|
86
86
|
{{on 'click' @onClick}}
|
|
87
87
|
>
|
|
88
88
|
{{#if @icon}}
|
|
89
|
-
|
|
89
|
+
{{! md icon is larger because tabler icons have extra padding which shrinks them }}
|
|
90
|
+
<@icon
|
|
91
|
+
class='pf-icon'
|
|
92
|
+
width={{if (eq @format 'markdown') '24' ICON_W}}
|
|
93
|
+
height={{if (eq @format 'markdown') '24' ICON_W}}
|
|
94
|
+
/>
|
|
90
95
|
{{/if}}
|
|
91
96
|
</Button>
|
|
92
97
|
<style scoped>
|
|
@@ -124,16 +129,10 @@ const FormatButton: TemplateOnlyComponent<FormatButtonSignature> = <template>
|
|
|
124
129
|
}
|
|
125
130
|
.pf-icon {
|
|
126
131
|
flex: 0 0 auto;
|
|
127
|
-
height: var(--pf-icon-w);
|
|
128
132
|
display: inline-flex;
|
|
129
133
|
align-items: center;
|
|
130
134
|
justify-content: center;
|
|
131
135
|
}
|
|
132
|
-
.pf-icon :deep(svg) {
|
|
133
|
-
height: var(--pf-icon-w);
|
|
134
|
-
width: auto;
|
|
135
|
-
display: block;
|
|
136
|
-
}
|
|
137
136
|
</style>
|
|
138
137
|
</template>;
|
|
139
138
|
|
|
@@ -430,7 +429,11 @@ export default class PillFormatChooser extends Component<Signature> {
|
|
|
430
429
|
</svg>
|
|
431
430
|
<div class='pill-content'>
|
|
432
431
|
{{#if this.pillTargetIcon}}
|
|
433
|
-
<this.pillTargetIcon
|
|
432
|
+
<this.pillTargetIcon
|
|
433
|
+
class='pf-icon'
|
|
434
|
+
width={{ICON_W}}
|
|
435
|
+
height={{ICON_W}}
|
|
436
|
+
/>
|
|
434
437
|
{{/if}}
|
|
435
438
|
<span
|
|
436
439
|
class='pf-label'
|
|
@@ -465,7 +465,7 @@ export default class ModuleInspector extends Component<ModuleInspectorSignature>
|
|
|
465
465
|
this.specSearch = this.getCards(
|
|
466
466
|
this,
|
|
467
467
|
() => this.queryForSpecsForSelectedDefinition,
|
|
468
|
-
() => this.realmServer.
|
|
468
|
+
() => this.realmServer.availableRealmIdentifiers,
|
|
469
469
|
{ isLive: true, doWhileRefreshing: this.doWhileRefreshing },
|
|
470
470
|
) as ReturnType<getCards<Spec>>;
|
|
471
471
|
};
|
package/bundled-types/host-app/components/operator-mode/code-submode/playground/playground-panel.gts
CHANGED
|
@@ -360,7 +360,7 @@ export default class PlaygroundPanel extends Component<Signature> {
|
|
|
360
360
|
this.fileSearchResults = this.getCards(
|
|
361
361
|
this,
|
|
362
362
|
() => this.fileMetaQuery,
|
|
363
|
-
() => this.realmServer.
|
|
363
|
+
() => this.realmServer.availableRealmIdentifiers,
|
|
364
364
|
{ isLive: true },
|
|
365
365
|
);
|
|
366
366
|
};
|
|
@@ -997,7 +997,7 @@ export default class PlaygroundPanel extends Component<Signature> {
|
|
|
997
997
|
<PrerenderedCardSearch
|
|
998
998
|
@query={{this.expandedQuery}}
|
|
999
999
|
@format='fitted'
|
|
1000
|
-
@realms={{this.realmServer.
|
|
1000
|
+
@realms={{this.realmServer.availableRealmIdentifiers}}
|
|
1001
1001
|
>
|
|
1002
1002
|
<:response as |maybeCards|>
|
|
1003
1003
|
{{! TODO: remove side-effects for instance chooser in CS-8746 }}
|
|
@@ -1139,7 +1139,7 @@ export default class PlaygroundPanel extends Component<Signature> {
|
|
|
1139
1139
|
{{else if this.maybeGenerateFieldSpec}}
|
|
1140
1140
|
<SpecSearch
|
|
1141
1141
|
@query={{this.specQuery}}
|
|
1142
|
-
@realms={{this.realmServer.
|
|
1142
|
+
@realms={{this.realmServer.availableRealmIdentifiers}}
|
|
1143
1143
|
@createNewCard={{this.createNew}}
|
|
1144
1144
|
/>
|
|
1145
1145
|
{{else if @isFileDef}}
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
RealmPaths,
|
|
40
40
|
Deferred,
|
|
41
41
|
SupportedMimeType,
|
|
42
|
-
|
|
42
|
+
maybeRelativeReference,
|
|
43
43
|
GetCardContextName,
|
|
44
44
|
isCardInstance,
|
|
45
45
|
type getCard,
|
|
@@ -844,7 +844,7 @@ export default class CreateFileModal extends Component<Signature> {
|
|
|
844
844
|
) as ResolvedCodeRef
|
|
845
845
|
).module;
|
|
846
846
|
const absoluteModule = new URL(absoluteModuleHref);
|
|
847
|
-
let moduleURL =
|
|
847
|
+
let moduleURL = maybeRelativeReference(
|
|
848
848
|
absoluteModule,
|
|
849
849
|
url,
|
|
850
850
|
new URL(this.selectedRealmURL),
|
|
@@ -10,6 +10,8 @@ import { BoxelSelect } from '@cardstack/boxel-ui/components';
|
|
|
10
10
|
import { IconGlobe, Lock, StarFilled } from '@cardstack/boxel-ui/icons';
|
|
11
11
|
import type { Icon } from '@cardstack/boxel-ui/icons';
|
|
12
12
|
|
|
13
|
+
import { ri } from '@cardstack/runtime-common';
|
|
14
|
+
|
|
13
15
|
import config from '@cardstack/host/config/environment';
|
|
14
16
|
import type MatrixService from '@cardstack/host/services/matrix-service';
|
|
15
17
|
import type RealmService from '@cardstack/host/services/realm';
|
|
@@ -54,13 +56,13 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
54
56
|
|
|
55
57
|
private get displayCatalogWorkspaces() {
|
|
56
58
|
return (
|
|
57
|
-
this.realmServer.
|
|
58
|
-
this.realmServer.
|
|
59
|
+
this.realmServer.displayedCatalogRealmIdentifiers &&
|
|
60
|
+
this.realmServer.displayedCatalogRealmIdentifiers.length > 0
|
|
59
61
|
);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
private get
|
|
63
|
-
let realmURLs = this.realmServer.
|
|
64
|
+
private get communityRealmIdentifiers() {
|
|
65
|
+
let realmURLs = this.realmServer.displayedCatalogRealmIdentifiers ?? [];
|
|
64
66
|
if (config.environment !== 'production') {
|
|
65
67
|
return realmURLs;
|
|
66
68
|
}
|
|
@@ -78,35 +80,35 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
78
80
|
);
|
|
79
81
|
};
|
|
80
82
|
|
|
81
|
-
private filterByHosted(urls:
|
|
83
|
+
private filterByHosted<T extends string>(urls: T[]): T[] {
|
|
82
84
|
if (this.sortOrder === 'hosted-only') {
|
|
83
85
|
return urls.filter(this.isHosted);
|
|
84
86
|
}
|
|
85
87
|
return urls;
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
private get
|
|
89
|
-
return this.filterByHosted(this.realmServer.
|
|
90
|
+
private get filteredUserRealmIdentifiers() {
|
|
91
|
+
return this.filterByHosted(this.realmServer.userRealmIdentifiers);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
private get
|
|
93
|
-
return this.filterByHosted(this.
|
|
94
|
+
private get filteredCatalogRealmIdentifiers() {
|
|
95
|
+
return this.filterByHosted(this.communityRealmIdentifiers);
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
private get
|
|
98
|
+
private get favoriteRealmIdentifiers() {
|
|
97
99
|
let favorites = this.matrixService.workspaceFavorites;
|
|
98
|
-
let allURLs = [
|
|
99
|
-
...this.realmServer.
|
|
100
|
-
...(this.realmServer.
|
|
101
|
-
];
|
|
102
|
-
let filtered = favorites.filter((url) => allURLs.
|
|
100
|
+
let allURLs = new Set<string>([
|
|
101
|
+
...this.realmServer.userRealmIdentifiers,
|
|
102
|
+
...(this.realmServer.displayedCatalogRealmIdentifiers ?? []),
|
|
103
|
+
]);
|
|
104
|
+
let filtered = favorites.filter((url) => allURLs.has(url)).map(ri);
|
|
103
105
|
return this.filterByHosted(filtered);
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
private get userWorkspacesEmptyMessage(): string | null {
|
|
107
109
|
if (
|
|
108
110
|
this.sortOrder === 'hosted-only' &&
|
|
109
|
-
this.
|
|
111
|
+
this.filteredUserRealmIdentifiers.length === 0
|
|
110
112
|
) {
|
|
111
113
|
return 'No matching results';
|
|
112
114
|
}
|
|
@@ -116,7 +118,7 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
116
118
|
private get catalogEmptyMessage(): string | null {
|
|
117
119
|
if (
|
|
118
120
|
this.sortOrder === 'hosted-only' &&
|
|
119
|
-
this.
|
|
121
|
+
this.filteredCatalogRealmIdentifiers.length === 0
|
|
120
122
|
) {
|
|
121
123
|
return 'No matching results';
|
|
122
124
|
}
|
|
@@ -127,7 +129,7 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
127
129
|
if (this.matrixService.workspaceFavorites.length === 0) {
|
|
128
130
|
return 'You have no favorites yet';
|
|
129
131
|
}
|
|
130
|
-
if (this.
|
|
132
|
+
if (this.favoriteRealmIdentifiers.length === 0) {
|
|
131
133
|
return 'No matching results';
|
|
132
134
|
}
|
|
133
135
|
return null;
|
|
@@ -168,8 +170,8 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
168
170
|
>{{this.favoritesEmptyMessage}}</span>
|
|
169
171
|
{{else}}
|
|
170
172
|
<div class='workspace-list' data-test-favorites-list>
|
|
171
|
-
{{#each this.
|
|
172
|
-
<Workspace @
|
|
173
|
+
{{#each this.favoriteRealmIdentifiers as |realmIdentifier|}}
|
|
174
|
+
<Workspace @realmIdentifier={{realmIdentifier}} />
|
|
173
175
|
{{/each}}
|
|
174
176
|
</div>
|
|
175
177
|
{{/if}}
|
|
@@ -186,8 +188,11 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
186
188
|
>{{this.userWorkspacesEmptyMessage}}</span>
|
|
187
189
|
{{else}}
|
|
188
190
|
<div class='workspace-list' data-test-workspace-list>
|
|
189
|
-
{{#each this.
|
|
190
|
-
<Workspace
|
|
191
|
+
{{#each this.filteredUserRealmIdentifiers as |realmIdentifier|}}
|
|
192
|
+
<Workspace
|
|
193
|
+
@realmIdentifier={{realmIdentifier}}
|
|
194
|
+
@showMenu={{true}}
|
|
195
|
+
/>
|
|
191
196
|
{{/each}}
|
|
192
197
|
{{#if this.matrixService.isInitializingNewUser}}
|
|
193
198
|
<WorkspaceLoadingIndicator />
|
|
@@ -209,8 +214,11 @@ export default class WorkspaceChooser extends Component<Signature> {
|
|
|
209
214
|
>{{this.catalogEmptyMessage}}</span>
|
|
210
215
|
{{else}}
|
|
211
216
|
<div class='workspace-list' data-test-catalog-list>
|
|
212
|
-
{{#each
|
|
213
|
-
|
|
217
|
+
{{#each
|
|
218
|
+
this.filteredCatalogRealmIdentifiers
|
|
219
|
+
as |realmIdentifier|
|
|
220
|
+
}}
|
|
221
|
+
<Workspace @realmIdentifier={{realmIdentifier}} />
|
|
214
222
|
{{/each}}
|
|
215
223
|
</div>
|
|
216
224
|
{{/if}}
|
|
@@ -33,8 +33,8 @@ import {
|
|
|
33
33
|
import {
|
|
34
34
|
hasExecutableExtension,
|
|
35
35
|
RealmPaths,
|
|
36
|
-
ri,
|
|
37
36
|
SupportedMimeType,
|
|
37
|
+
type RealmIdentifier,
|
|
38
38
|
} from '@cardstack/runtime-common';
|
|
39
39
|
|
|
40
40
|
import ModalContainer from '@cardstack/host/components/modal-container';
|
|
@@ -51,7 +51,7 @@ import WorkspaceLoadingIndicator from './workspace-loading-indicator';
|
|
|
51
51
|
interface Signature {
|
|
52
52
|
Element: HTMLDivElement;
|
|
53
53
|
Args: {
|
|
54
|
-
|
|
54
|
+
realmIdentifier: RealmIdentifier;
|
|
55
55
|
showMenu?: boolean;
|
|
56
56
|
};
|
|
57
57
|
}
|
|
@@ -93,7 +93,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
93
93
|
@width='16'
|
|
94
94
|
@height='16'
|
|
95
95
|
{{on 'click' this.toggleFavorite}}
|
|
96
|
-
data-test-workspace-favorite-btn={{@
|
|
96
|
+
data-test-workspace-favorite-btn={{@realmIdentifier}}
|
|
97
97
|
/>
|
|
98
98
|
<div class='tile-menu-btn'>
|
|
99
99
|
<BoxelDropdown>
|
|
@@ -103,7 +103,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
103
103
|
@variant='ghost'
|
|
104
104
|
@width='16'
|
|
105
105
|
@height='16'
|
|
106
|
-
data-test-workspace-menu-trigger={{@
|
|
106
|
+
data-test-workspace-menu-trigger={{@realmIdentifier}}
|
|
107
107
|
{{bindings}}
|
|
108
108
|
/>
|
|
109
109
|
</:trigger>
|
|
@@ -116,7 +116,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
116
116
|
<button
|
|
117
117
|
class='host-trigger'
|
|
118
118
|
type='button'
|
|
119
|
-
data-test-host-trigger={{@
|
|
119
|
+
data-test-host-trigger={{@realmIdentifier}}
|
|
120
120
|
{{on 'click' this.toggleHostDropdown}}
|
|
121
121
|
>
|
|
122
122
|
<span class='trigger-house'><Home width='13' height='13' /></span>
|
|
@@ -127,7 +127,10 @@ export default class Workspace extends Component<Signature> {
|
|
|
127
127
|
</button>
|
|
128
128
|
|
|
129
129
|
{{#if this.isHostDropdownOpen}}
|
|
130
|
-
<div
|
|
130
|
+
<div
|
|
131
|
+
class='host-dropdown'
|
|
132
|
+
data-test-host-dropdown={{@realmIdentifier}}
|
|
133
|
+
>
|
|
131
134
|
<span class='dropdown-header'>Launch in new window</span>
|
|
132
135
|
<ul class='dropdown-list'>
|
|
133
136
|
{{#each this.publishedRealmURLs as |url|}}
|
|
@@ -179,7 +182,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
179
182
|
@size='medium'
|
|
180
183
|
@cardContainerClass='workspace-chooser-delete-modal'
|
|
181
184
|
class='workspace-chooser-delete-modal-container'
|
|
182
|
-
data-test-delete-modal={{@
|
|
185
|
+
data-test-delete-modal={{@realmIdentifier}}
|
|
183
186
|
>
|
|
184
187
|
<:content>
|
|
185
188
|
<div class='delete-modal__header'>
|
|
@@ -773,7 +776,9 @@ export default class Workspace extends Component<Signature> {
|
|
|
773
776
|
</template>
|
|
774
777
|
|
|
775
778
|
get isFavorited() {
|
|
776
|
-
return this.matrixService.workspaceFavorites.includes(
|
|
779
|
+
return this.matrixService.workspaceFavorites.includes(
|
|
780
|
+
this.args.realmIdentifier,
|
|
781
|
+
);
|
|
777
782
|
}
|
|
778
783
|
|
|
779
784
|
@service declare private operatorModeStateService: OperatorModeStateService;
|
|
@@ -794,13 +799,13 @@ export default class Workspace extends Component<Signature> {
|
|
|
794
799
|
}
|
|
795
800
|
|
|
796
801
|
private loadRealmTask = task(async () => {
|
|
797
|
-
await this.realm.login(this.args.
|
|
798
|
-
await this.realm.ensureRealmMeta(this.args.
|
|
802
|
+
await this.realm.login(this.args.realmIdentifier);
|
|
803
|
+
await this.realm.ensureRealmMeta(this.args.realmIdentifier);
|
|
799
804
|
});
|
|
800
805
|
|
|
801
806
|
@cached
|
|
802
807
|
private get realmInfo() {
|
|
803
|
-
return this.realm.info(this.args.
|
|
808
|
+
return this.realm.info(this.args.realmIdentifier);
|
|
804
809
|
}
|
|
805
810
|
|
|
806
811
|
private get name() {
|
|
@@ -826,9 +831,11 @@ export default class Workspace extends Component<Signature> {
|
|
|
826
831
|
|
|
827
832
|
@action async toggleFavorite() {
|
|
828
833
|
if (this.isFavorited) {
|
|
829
|
-
await this.matrixService.removeWorkspaceFavorite(
|
|
834
|
+
await this.matrixService.removeWorkspaceFavorite(
|
|
835
|
+
this.args.realmIdentifier,
|
|
836
|
+
);
|
|
830
837
|
} else {
|
|
831
|
-
await this.matrixService.addWorkspaceFavorite(this.args.
|
|
838
|
+
await this.matrixService.addWorkspaceFavorite(this.args.realmIdentifier);
|
|
832
839
|
}
|
|
833
840
|
}
|
|
834
841
|
|
|
@@ -900,7 +907,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
900
907
|
}
|
|
901
908
|
|
|
902
909
|
private get canDeleteWorkspace() {
|
|
903
|
-
return this.realm.isRealmOwner(this.args.
|
|
910
|
+
return this.realm.isRealmOwner(this.args.realmIdentifier);
|
|
904
911
|
}
|
|
905
912
|
|
|
906
913
|
private get deleteSummaryText() {
|
|
@@ -933,7 +940,9 @@ export default class Workspace extends Component<Signature> {
|
|
|
933
940
|
}
|
|
934
941
|
|
|
935
942
|
@action async openWorkspace() {
|
|
936
|
-
await this.operatorModeStateService.openWorkspace(
|
|
943
|
+
await this.operatorModeStateService.openWorkspace(
|
|
944
|
+
this.args.realmIdentifier,
|
|
945
|
+
);
|
|
937
946
|
}
|
|
938
947
|
|
|
939
948
|
@action openDeleteModal() {
|
|
@@ -957,7 +966,7 @@ export default class Workspace extends Component<Signature> {
|
|
|
957
966
|
private loadDeleteSummaryTask = dropTask(async () => {
|
|
958
967
|
try {
|
|
959
968
|
let response = await this.network.authedFetch(
|
|
960
|
-
`${this.args.
|
|
969
|
+
`${this.args.realmIdentifier}_mtimes`,
|
|
961
970
|
{
|
|
962
971
|
headers: {
|
|
963
972
|
Accept: SupportedMimeType.Mtimes,
|
|
@@ -989,23 +998,27 @@ export default class Workspace extends Component<Signature> {
|
|
|
989
998
|
this.deleteError = undefined;
|
|
990
999
|
|
|
991
1000
|
try {
|
|
992
|
-
let realmPath = new RealmPaths(
|
|
1001
|
+
let realmPath = new RealmPaths(this.args.realmIdentifier);
|
|
993
1002
|
let isActiveWorkspace =
|
|
994
|
-
this.operatorModeStateService.realmURL === this.args.
|
|
1003
|
+
this.operatorModeStateService.realmURL === this.args.realmIdentifier ||
|
|
995
1004
|
this.operatorModeStateService
|
|
996
1005
|
.getOpenCardIds()
|
|
997
1006
|
.some((cardId) => realmPath.inRealm(cardId)) ||
|
|
998
1007
|
this.operatorModeStateService.codePathString?.startsWith(
|
|
999
|
-
this.args.
|
|
1008
|
+
this.args.realmIdentifier,
|
|
1000
1009
|
);
|
|
1001
1010
|
|
|
1002
|
-
await this.realmServer.deleteRealm(this.args.
|
|
1003
|
-
await this.matrixService.removeRealmFromAccountData(
|
|
1004
|
-
|
|
1011
|
+
await this.realmServer.deleteRealm(this.args.realmIdentifier);
|
|
1012
|
+
await this.matrixService.removeRealmFromAccountData(
|
|
1013
|
+
this.args.realmIdentifier,
|
|
1014
|
+
);
|
|
1015
|
+
this.recentFilesService.removeRecentFilesForRealmURL(
|
|
1016
|
+
this.args.realmIdentifier,
|
|
1017
|
+
);
|
|
1005
1018
|
for (let publishedRealmURL of this.publishedRealmURLs) {
|
|
1006
1019
|
this.recentFilesService.removeRecentFilesForRealmURL(publishedRealmURL);
|
|
1007
1020
|
}
|
|
1008
|
-
this.realm.removeRealm(this.args.
|
|
1021
|
+
this.realm.removeRealm(this.args.realmIdentifier);
|
|
1009
1022
|
|
|
1010
1023
|
if (isActiveWorkspace) {
|
|
1011
1024
|
this.operatorModeStateService.clearStacks();
|
|
@@ -36,7 +36,7 @@ export default class RealmPicker extends Component<Signature> {
|
|
|
36
36
|
// interprets as a user-initiated filter change (expanding the search sheet).
|
|
37
37
|
@cached
|
|
38
38
|
get selectAllOption(): PickerOption {
|
|
39
|
-
const urls = this.realmServer.
|
|
39
|
+
const urls = this.realmServer.availableRealmIdentifiers;
|
|
40
40
|
return {
|
|
41
41
|
id: 'select-all',
|
|
42
42
|
label: `Select All (${urls.length})`,
|
|
@@ -60,7 +60,7 @@ export default class RealmPicker extends Component<Signature> {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
get realmOptions(): PickerOption[] {
|
|
63
|
-
const urls = this.realmServer.
|
|
63
|
+
const urls = this.realmServer.availableRealmIdentifiers;
|
|
64
64
|
const options: PickerOption[] = [this.selectAllOption];
|
|
65
65
|
for (const realmURL of urls) {
|
|
66
66
|
const info = this.realm.info(realmURL);
|
|
@@ -197,7 +197,7 @@ export default class SearchSheet extends Component<Signature> {
|
|
|
197
197
|
private get searchKeyAsURL() {
|
|
198
198
|
return resolveSearchKeyAsURL(
|
|
199
199
|
this.searchKey,
|
|
200
|
-
this.realmServer.
|
|
200
|
+
this.realmServer.availableRealmIdentifiers,
|
|
201
201
|
);
|
|
202
202
|
}
|
|
203
203
|
|
|
@@ -23,7 +23,7 @@ export default class WithKnownRealmsLoaded extends Component<Signature> {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
private loadRealmsTask = task(async () => {
|
|
26
|
-
let realmURLs = this.realmServer.
|
|
26
|
+
let realmURLs = this.realmServer.availableRealmIdentifiers;
|
|
27
27
|
await Promise.all(
|
|
28
28
|
realmURLs.map(
|
|
29
29
|
async (realmURL) => await this.realm.ensureRealmMeta(realmURL),
|
|
@@ -19,6 +19,16 @@ function ensureSingleTitle(headHTML: string): string {
|
|
|
19
19
|
? headHTML
|
|
20
20
|
: `${DEFAULT_HEAD_HTML}\n${headHTML}`;
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
// Normalize trailing-slash variance for routing-map matching. `/realm/`
|
|
24
|
+
// and `/realm` are the same destination from the user's perspective,
|
|
25
|
+
// but the injected map keys and Ember's `params.path` disagree on
|
|
26
|
+
// the trailing slash. Stripping it on both sides makes the comparator
|
|
27
|
+
// robust. Preserve the root `/` since stripping it would empty the path.
|
|
28
|
+
function canonicalizeRoutingPath(path: string): string {
|
|
29
|
+
if (path === '/') return '/';
|
|
30
|
+
return path.replace(/\/+$/, '');
|
|
31
|
+
}
|
|
22
32
|
import type HostModeStateService from '@cardstack/host/services/host-mode-state-service';
|
|
23
33
|
import type OperatorModeStateService from '@cardstack/host/services/operator-mode-state-service';
|
|
24
34
|
import type RealmService from '@cardstack/host/services/realm';
|
|
@@ -130,10 +140,19 @@ export default class HostModeService extends Service {
|
|
|
130
140
|
// `https://host/<user>/<realm>/whitepaper`); a leading slash is added if
|
|
131
141
|
// absent so the index path is matchable as either '' or '/'. The
|
|
132
142
|
// server prefixes each rule's `path` with the realm's mount pathname
|
|
133
|
-
// before injecting the map, so the two sides line up as direct equality
|
|
143
|
+
// before injecting the map, so the two sides line up as direct equality
|
|
144
|
+
// — except for the trailing-slash variance at the realm root. A `/`
|
|
145
|
+
// rule's injected key is the realm's mount pathname WITH trailing
|
|
146
|
+
// slash (e.g. `/progressive-cheetah/`), but Ember's catch-all strips
|
|
147
|
+
// it (`params.path === 'progressive-cheetah'` for either visit form).
|
|
148
|
+
// Canonicalize both sides by stripping trailing slashes (except the
|
|
149
|
+
// root `/` itself) before comparing so `/realm` ↔ `/realm/` resolve.
|
|
134
150
|
resolveRoutedPath(path: string): string | null {
|
|
135
151
|
let normalized = path.startsWith('/') ? path : `/${path}`;
|
|
136
|
-
let
|
|
152
|
+
let canonical = canonicalizeRoutingPath(normalized);
|
|
153
|
+
let rule = this.hostRoutingMap.find(
|
|
154
|
+
(r) => canonicalizeRoutingPath(r.path) === canonical,
|
|
155
|
+
);
|
|
137
156
|
return rule ? rule.id : null;
|
|
138
157
|
}
|
|
139
158
|
|