Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 12 additions & 4 deletions packages/host/app/components/operator-mode/create-file-modal.gts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from '@cardstack/boxel-ui/icons';

import {
cardIdToURL,
specRef,
chooseCard,
baseRealm,
Expand Down Expand Up @@ -826,7 +827,16 @@ export default class CreateFileModal extends Component<Signature> {
ref: { name: exportName, module },
} = (this.definitionClass ?? spec)!; // we just checked above to make sure one of these exists
let className = convertToClassName(this.displayName);
let absoluteModule = new URL(module, spec?.id);
const absoluteModuleHref = (
codeRefWithAbsoluteURL(
{
module: spec?.moduleHref ?? module,
name: exportName,
},
new URL(this.selectedRealmURL),
) as ResolvedCodeRef
).module;
const absoluteModule = new URL(absoluteModuleHref);
let moduleURL = maybeRelativeURL(
absoluteModule,
url,
Expand Down Expand Up @@ -929,9 +939,7 @@ export class ${className} extends ${exportName} {

let { ref } = (this.definitionClass ? this.definitionClass : spec)!; // we just checked above to make sure one of these exist

let relativeTo = spec
? new URL(spec.id!) // only new cards are missing urls
: undefined;
let relativeTo = spec?.id ? cardIdToURL(spec.id) : undefined;
// we make the code ref use an absolute URL for safety in
// the case it's being created in a different realm than where the card
// definition comes from. The server will make relative URL if appropriate after creation
Expand Down
95 changes: 94 additions & 1 deletion packages/host/tests/acceptance/code-submode/create-file-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import {
import { getService } from '@universal-ember/test-support';
import { module, test } from 'qunit';

import { baseRealm, Deferred } from '@cardstack/runtime-common';
import {
baseRealm,
Deferred,
registerCardReferencePrefix,
unregisterCardReferencePrefix,
} from '@cardstack/runtime-common';

import type FileUploadService from '@cardstack/host/services/file-upload';

Expand Down Expand Up @@ -37,6 +42,8 @@ import type { TestRealmAdapter } from '../../helpers/adapter';
const testRealmURL2 = 'http://test-realm/test2/';
const testRealmAIconURL = 'https://i.postimg.cc/L8yXRvws/icon.png';

const testPrefixRealmURL2 = `@test-realm/test2/`;

const files: Record<string, any> = {
'.realm.json': {
name: 'Test Workspace A',
Expand Down Expand Up @@ -183,6 +190,32 @@ const filesB: Record<string, any> = {
},
},
},
'animal.gts': `
import { contains, field, CardDef } from "https://cardstack.com/base/card-api";
import StringField from "https://cardstack.com/base/string";

export class Animal extends CardDef {
static displayName = 'Animal';
@field name = contains(StringField);
}
`,
'spec/animal.json': {
data: {
type: 'card',
attributes: {
cardTitle: 'Animal',
cardDescription: 'Spec for Animal',
specType: 'card',
ref: { module: '@test-realm/test2/animal', name: 'Animal' },
},
meta: {
adoptsFrom: {
module: 'https://cardstack.com/base/spec',
name: 'Spec',
},
},
},
},
};

module('Acceptance | code submode | create-file tests', function (hooks) {
Expand Down Expand Up @@ -1234,6 +1267,66 @@ export class TestCard extends CardDef {
});
});

module('when a selected spec uses a prefix-form ref', function (hooks) {
hooks.before(function () {
registerCardReferencePrefix(testPrefixRealmURL2, testRealmURL2);
});

hooks.after(function () {
unregisterCardReferencePrefix(testPrefixRealmURL2);
});

test<TestContextWithSave>('can create new card definition in workspace A that extends a card from workspace B via prefix-form ref', async function (assert) {
assert.expect(2);
await visitOperatorMode(`${baseRealm.url}card-api.gts`);
await openNewFileModal('Card Definition');
await click('[data-test-select-card-type]');
await waitFor('[data-test-card-catalog-modal]');
await waitFor(
`[data-test-card-catalog-item="${testRealmURL2}spec/animal"]`,
);
await click(
`[data-test-card-catalog-item="${testRealmURL2}spec/animal"]`,
);
await click('[data-test-card-catalog-go-button]');
await waitFor(`[data-test-selected-type="Animal"]`);

await fillIn('[data-test-display-name-field]', 'Test Card');
await fillIn('[data-test-file-name-field]', 'test-card');

let deferred = new Deferred<void>();
this.onSave((url, content) => {
if (typeof content !== 'string') {
throw new Error(`expected string save data`);
}
assert.strictEqual(
content,
`
import { Animal } from '${testRealmURL2}animal';
import { Component } from 'https://cardstack.com/base/card-api';
export class TestCard extends Animal {
static displayName = "Test Card";
}`.trim(),
'The source uses the resolved absolute module URL',
);
assert.strictEqual(
url.href,
`${testRealmURL}test-card.gts`,
[
'Saved file URL should point to Test Workspace A',
`Expected: ${testRealmURL}test-card.gts`,
`Actual: ${url.href}`,
].join('\n'),
);
deferred.fulfill();
});

await click('[data-test-create-definition]');
await waitFor('[data-test-create-file-modal]', { count: 0 });
await deferred.promise;
});
});

module(
'when the user lacks write permissions in remote realm',
function (hooks) {
Expand Down
Loading