Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions packages/base/card-api.gts
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,7 @@ export type ViewCardFn = (
cardOrURL: CardDef | URL,
format?: Format,
opts?: {
type?: 'card' | 'file';
openCardInRightMostStack?: boolean;
stackIndex?: number;
fieldType?: 'linksTo' | 'contains' | 'containsMany' | 'linksToMany';
Expand Down
5 changes: 4 additions & 1 deletion packages/base/links-to-editor.gts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ export class LinksToEditor extends GlimmerComponent<Signature> {
/>
{{/if}}
<DefaultFormatsProvider
@value={{hash cardDef='fitted' fieldDef='embedded'}}
@value={{hash
cardDef='fitted'
fieldDef='embedded'
}}
>
<this.linkedCard />
</DefaultFormatsProvider>
Expand Down
22 changes: 21 additions & 1 deletion packages/host/app/components/operator-mode/interact-submode.gts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ import {

import CopyCardToStackCommand from '@cardstack/host/commands/copy-card-to-stack';

import { StackItem } from '@cardstack/host/lib/stack-item';
import {
detectStackItemTypeForTarget,
StackItem,
type StackItemType,
} from '@cardstack/host/lib/stack-item';

import { stackBackgroundsResource } from '@cardstack/host/resources/stack-backgrounds';

Expand Down Expand Up @@ -186,6 +190,7 @@ export default class InteractSubmode extends Component {
request: new Deferred(),
closeAfterSaving: opts?.closeAfterCreating,
stackIndex,
type: 'card',
});
this.addToStack(newItem);
return localId;
Expand All @@ -196,6 +201,7 @@ export default class InteractSubmode extends Component {
cardOrURL: CardDef | URL | string,
format: Format | Event = 'isolated',
opts?: {
type?: StackItemType;
openCardInRightMostStack?: boolean;
stackIndex?: number;
fieldType?: 'linksTo' | 'linksToMany' | 'contains' | 'containsMany';
Expand All @@ -212,6 +218,9 @@ export default class InteractSubmode extends Component {
: cardOrURL instanceof URL
? cardOrURL.href
: cardOrURL.id;
if (!cardId) {
return;
}
if (opts?.openCardInRightMostStack) {
stackIndex = this.stacks.length;
} else if (typeof opts?.stackIndex === 'number') {
Expand All @@ -229,10 +238,12 @@ export default class InteractSubmode extends Component {
}
stackIndex = opts.stackIndex;
}
let stackItemType = opts?.type ?? this.getStackItemType(cardOrURL, cardId);
let newItem = new StackItem({
id: cardId,
format,
stackIndex,
type: stackItemType,
relationshipContext: opts?.fieldName
? {
fieldName: opts.fieldName,
Expand All @@ -251,6 +262,13 @@ export default class InteractSubmode extends Component {
this.operatorModeStateService.editCardOnStack(stackIndex, card);
};

private getStackItemType(
cardOrURL: CardDef | URL | string,
cardId: string,
): StackItemType {
return detectStackItemTypeForTarget(cardOrURL, cardId, this.store);
}

private saveCard = (id: string): void => {
this.store.save(id);
};
Expand Down Expand Up @@ -500,6 +518,7 @@ export default class InteractSubmode extends Component {
id: url.href,
format: 'isolated',
stackIndex: 0,
type: this.getStackItemType(url, url.href),
});
// it's important that we await the stack item readiness _before_
// we mutate the stack, otherwise there are very odd visual artifacts
Expand Down Expand Up @@ -542,6 +561,7 @@ export default class InteractSubmode extends Component {
id: url.href,
format: 'isolated',
stackIndex,
type: this.getStackItemType(url, url.href),
});
// await stackItem.ready();
this.operatorModeStateService.clearStackAndAdd(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { array, fn } from '@ember/helper';
import { on } from '@ember/modifier';
import { action } from '@ember/object';
import { service } from '@ember/service';

import { consume } from 'ember-provide-consume-context';
import { velcro } from 'ember-velcro';
Expand Down Expand Up @@ -32,6 +33,7 @@ import {
} from '@cardstack/boxel-ui/icons';

import type { CommandContext } from '@cardstack/runtime-common';

import {
CardCrudFunctionsContextName,
CommandContextName,
Expand All @@ -44,16 +46,20 @@ import type {
Format,
} from 'https://cardstack.com/base/card-api';

import { detectStackItemTypeForTarget } from '../../lib/stack-item';

import { removeFileExtension } from '../card-search/utils';

import Overlays from './overlays';

import type { StackItemRenderedCardForOverlayActions } from './stack-item';

import type { CardDefOrId } from './stack-item';
import type StoreService from '../../services/store';

export default class OperatorModeOverlays extends Overlays {
overlayClassName = 'actions-overlay';
@service declare private store: StoreService;

@consume(CardCrudFunctionsContextName)
declare private cardCrudFunctions: CardCrudFunctions;
Expand Down Expand Up @@ -345,6 +351,9 @@ export default class OperatorModeOverlays extends Overlays {
case 'select':
return !this.isField(renderedCard) && !!this.args.toggleSelect;
case 'edit':
if (this.isFileMetaTarget(renderedCard)) {
return false;
}
return this.realm.canWrite(this.getCardId(renderedCard.cardDefOrId));
case 'more-options':
return true;
Expand All @@ -353,6 +362,36 @@ export default class OperatorModeOverlays extends Overlays {
}
}

private isFileMetaTarget(
renderedCard: StackItemRenderedCardForOverlayActions,
): boolean {
return this.getTypeForCardTarget(renderedCard.cardDefOrId) === 'file';
}

private getTypeForCardTarget(cardDefOrId: CardDefOrId): 'card' | 'file' {
return detectStackItemTypeForTarget(
cardDefOrId,
this.getCardId(cardDefOrId),
this.store,
);
}

protected override buildViewCardOpts(
cardDefOrId: CardDefOrId,
fieldType?: 'linksTo' | 'contains' | 'containsMany' | 'linksToMany',
fieldName?: string,
): {
type?: 'card' | 'file';
fieldType?: 'linksTo' | 'contains' | 'containsMany' | 'linksToMany';
fieldName?: string;
} {
return {
type: this.getTypeForCardTarget(cardDefOrId),
fieldType,
fieldName,
};
}

@action
private registerDropdownAPI(
renderedCard: StackItemRenderedCardForOverlayActions,
Expand Down Expand Up @@ -398,6 +437,9 @@ export default class OperatorModeOverlays extends Overlays {
protected override getFormatForCard(
renderedCard: StackItemRenderedCardForOverlayActions,
): Format {
if (this.isFileMetaTarget(renderedCard)) {
return 'isolated';
}
return renderedCard.stackItem.format as Format;
}

Expand Down
26 changes: 22 additions & 4 deletions packages/host/app/components/operator-mode/overlays.gts
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,32 @@ export default class Overlays extends Component<OverlaySignature> {
let canWrite = this.realm.canWrite(cardId);
format = canWrite ? format : 'isolated';
if (this.args.viewCard) {
await this.args.viewCard(new URL(cardId), format, {
fieldType,
fieldName,
});
let target =
typeof cardDefOrId === 'string' ? new URL(cardId) : cardDefOrId;
await this.args.viewCard(
target,
format,
this.buildViewCardOpts(cardDefOrId, fieldType, fieldName),
);
}
},
);

protected buildViewCardOpts(
_cardDefOrId: CardDefOrId,
fieldType?: 'linksTo' | 'contains' | 'containsMany' | 'linksToMany',
fieldName?: string,
): {
type?: 'card' | 'file';
fieldType?: 'linksTo' | 'contains' | 'containsMany' | 'linksToMany';
fieldName?: string;
} {
return {
fieldType,
fieldName,
};
}

protected zIndexStyle(element: HTMLElement, overlayZIndexStyle?: SafeString) {
if (overlayZIndexStyle) {
return overlayZIndexStyle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
getMenuItems,
identifyCard,
isCardInstance,
isFileDefInstance,
isResolvedCodeRef,
} from '@cardstack/runtime-common';

Expand Down Expand Up @@ -94,7 +95,11 @@ export default class PreviewPanel extends Component<Signature> {

private openInInteractMode = () => {
if (this.cardId) {
this.operatorModeStateService.openCardInInteractMode(this.cardId);
this.operatorModeStateService.openCardInInteractMode(
this.cardId,
'isolated',
isFileDefInstance(this.args.card) ? 'file' : 'card',
);
}
};

Expand Down
28 changes: 24 additions & 4 deletions packages/host/app/components/operator-mode/stack-item.gts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
type getCard,
type getCards,
type getCardCollection,
isFileDefInstance,
cardTypeDisplayName,
PermissionsContextName,
RealmURLContextName,
Expand All @@ -57,7 +58,10 @@ import {
getMenuItems,
} from '@cardstack/runtime-common';

import type { StackItem } from '@cardstack/host/lib/stack-item';
import {
stackItemTypeToStoreReadType,
type StackItem,
} from '@cardstack/host/lib/stack-item';
import { urlForRealmLookup } from '@cardstack/host/lib/utils';

import type {
Expand Down Expand Up @@ -178,7 +182,9 @@ export default class OperatorModeStackItem extends Component<Signature> {
}

private makeCardResource = () => {
this.cardResource = this.getCard(this, () => this.args.item.id);
this.cardResource = this.getCard(this, () => this.args.item.id, {
type: stackItemTypeToStoreReadType(this.args.item.type),
});
};

private get url() {
Expand Down Expand Up @@ -654,12 +660,26 @@ export default class OperatorModeStackItem extends Component<Signature> {
this.card[realmURL] &&
!this.isBuried &&
!this.isEditing &&
!this.isFileCard &&
this.realm.canWrite(this.card[realmURL].href)
);
}

private get isEditing() {
return !this.isBuried && this.args.item.format === 'edit';
return (
!this.isBuried && !this.isFileCard && this.args.item.format === 'edit'
);
}

private get isFileCard() {
return (
this.args.item.type === 'file' ||
(this.card ? isFileDefInstance(this.card) : false)
);
}

private get cardFormat() {
return this.isFileCard ? 'isolated' : this.args.item.format;
}

private get showError() {
Expand Down Expand Up @@ -831,7 +851,7 @@ export default class OperatorModeStackItem extends Component<Signature> {
<CardRenderer
class='stack-item-preview'
@card={{this.card}}
@format={{@item.format}}
@format={{this.cardFormat}}
/>
<OperatorModeOverlays
@renderedCardsForOverlayActions={{this.renderedCardsForOverlayActions}}
Expand Down
Loading
Loading