Skip to content

Commit

Permalink
feat(vue3): support for ServiceViewModel in c-admin-method(s?)
Browse files Browse the repository at this point in the history
  • Loading branch information
ascott18 committed May 1, 2024
1 parent 081bf7f commit f733920
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ A metadata specifier for the method. One of:
- A direct reference to a method's metadata object.
- A string in dot-notation that starts with a type name and ending with a method name.

<Prop def="model: ViewModel | ListViewModel" lang="ts" />
<Prop def="model: ViewModel | ListViewModel | ServiceViewModel" lang="ts" />

An [ViewModel](/stacks/vue/layers/viewmodels.md) or [ListViewModel](/stacks/vue/layers/viewmodels.md) owning the method and [API Caller](/stacks/vue/layers/api-clients.md#api-callers) that was specified by the `for` prop.
An [ViewModel](/stacks/vue/layers/viewmodels.md) or [ListViewModel](/stacks/vue/layers/viewmodels.md) or [ServiceViewModel](/modeling/model-types/services.md#generated-code) owning the method and [API Caller](/stacks/vue/layers/api-clients.md#api-callers) that was specified by the `for` prop.

<Prop def="autoReloadModel?: boolean = false" lang="ts" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Renders in a [Vuetify](https://vuetifyjs.com/) [v-expansion-panels](https://vuet

<Prop def="model: ViewModel | ListViewModel" lang="ts" />

An [ViewModel](/stacks/vue/layers/viewmodels.md) or [ListViewModel](/stacks/vue/layers/viewmodels.md) whose methods should each render as a [c-admin-method](/stacks/vue/coalesce-vue-vuetify/components/c-admin-method.md).
An [ViewModel](/stacks/vue/layers/viewmodels.md) or [ListViewModel](/stacks/vue/layers/viewmodels.md) or [ServiceViewModel](/modeling/model-types/services.md#generated-code) whose methods should each render as a [c-admin-method](/stacks/vue/coalesce-vue-vuetify/components/c-admin-method.md).

<Prop def="autoReloadModel?: boolean = false" lang="ts" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CAdminMethod } from "..";
import {
PersonViewModel,
PersonListViewModel,
WeatherServiceViewModel,
} from "@test-targets/viewmodels.g";

describe("CAdminMethod", () => {
test("types", () => {
const vm = new PersonViewModel();
const listVm = new PersonListViewModel();
const serviceVm = new WeatherServiceViewModel();

const rename = vm.$metadata.methods.rename;
const getUser = listVm.$metadata.methods.getUser;
const getWeather = serviceVm.$metadata.methods.getWeather;

() => <CAdminMethod model={vm} for="rename" />;
() => <CAdminMethod model={vm} for={rename} />;
//@ts-expect-error method doesn't exist
() => <CAdminMethod model={vm} for="invalid" />;
//@ts-expect-error method from wrong type
() => <CAdminMethod model={vm} for={getWeather} />;

() => <CAdminMethod model={listVm} for="getUser" />;
() => <CAdminMethod model={listVm} for={getUser} />;
//@ts-expect-error method doesn't exist
() => <CAdminMethod model={listVm} for="invalid" />;
//@ts-expect-error method from wrong type
() => <CAdminMethod model={listVm} for={getWeather} />;

() => <CAdminMethod model={serviceVm} for="getWeather" />;
() => <CAdminMethod model={serviceVm} for={getWeather} />;
//@ts-expect-error method doesn't exist
() => <CAdminMethod model={serviceVm} for="invalid" />;
//@ts-expect-error method from wrong type
() => <CAdminMethod model={serviceVm} for={rename} />;
});
});
21 changes: 12 additions & 9 deletions src/coalesce-vue-vuetify3/src/components/admin/c-admin-method.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,13 @@
</div>
</template>

<script lang="ts" setup generic="TModel extends ViewModel | ListViewModel">
<script
lang="ts"
setup
generic="TModel extends ViewModel | ListViewModel | ServiceViewModel"
>
import { computed, ref } from "vue";
import { ViewModel, ListViewModel } from "coalesce-vue";
import { ViewModel, ListViewModel, ServiceViewModel } from "coalesce-vue";
import type {
DisplayOptions,
AnyArgCaller,
Expand Down Expand Up @@ -184,7 +188,7 @@ const props = defineProps<{
* * A string with the name of the method belonging to `model`. E.g. `"myMethod"`.
* * A direct reference to the metadata object. E.g. `model.$metadata.methods.myMethod`.
*/
for: MethodForSpec;
for: MethodForSpec<TModel>;
autoReloadModel?: boolean;
}>();
Expand Down Expand Up @@ -216,18 +220,17 @@ const caller = computed((): AnyArgCaller => {
return caller;
});
const viewModel = computed((): ViewModel | ListViewModel => {
const viewModel = computed((): TModel => {
if (props.model instanceof ViewModel) return props.model;
if (props.model instanceof ListViewModel) return props.model;
throw Error(
"c-method: prop `model` is required, and must be a ViewModel or ListViewModel."
);
if (props.model instanceof ServiceViewModel) return props.model;
throw Error("c-method: prop `model` is required, and must be a ViewModel.");
});
async function invoke() {
fileDownloadKind.value = "preview";
await caller.value.invokeWithArgs();
if (props.autoReloadModel) {
if (props.autoReloadModel && "$load" in viewModel.value) {
await viewModel.value.$load();
}
if (methodMeta.value.autoClear) {
Expand All @@ -239,7 +242,7 @@ async function invokeAndDownload() {
fileDownloadKind.value = "download";
await caller.value.invokeWithArgs();
if (props.autoReloadModel) {
if (props.autoReloadModel && "$load" in viewModel.value) {
// Don't await. Just do this in the background while we setup the file download.
viewModel.value.$load();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { CAdminMethods } from "..";
import {
PersonViewModel,
PersonListViewModel,
WeatherServiceViewModel,
} from "@test-targets/viewmodels.g";

describe("CAdminMethods", () => {
test("types", () => {
const vm = new PersonViewModel();
const listVm = new PersonListViewModel();
const serviceVm = new WeatherServiceViewModel();

const rename = vm.$metadata.methods.rename;

() => <CAdminMethods model={vm} />;
() => <CAdminMethods model={listVm} />;
() => <CAdminMethods model={serviceVm} />;

// @ts-expect-error not a model
() => <CAdminMethods model={rename} />;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<v-divider class="mx-4 my-0" vertical></v-divider>

<v-toolbar-title v-if="!isStatic">
<c-display :model="model"></c-display>
<v-toolbar-title v-if="'$primaryKey' in viewModel">
<c-display :model="viewModel"></c-display>
</v-toolbar-title>
</v-toolbar>
<v-expansion-panels class="c-methods">
Expand Down Expand Up @@ -38,21 +38,23 @@
<script lang="ts">
import { defineComponent } from "vue";
import {
Model,
ViewModel,
ModelType,
ListViewModel,
HiddenAreas,
ServiceViewModel,
} from "coalesce-vue";
import { PropType } from "vue";
type AnyViewModel = ViewModel | ListViewModel | ServiceViewModel;
export default defineComponent({
name: "c-admin-methods",
props: {
model: {
required: true,
type: Object as PropType<ViewModel<Model<ModelType>> | ListViewModel>,
type: Object as PropType<AnyViewModel>,
},
area: {
required: false,
Expand All @@ -63,11 +65,12 @@ export default defineComponent({
},
computed: {
viewModel(): ViewModel | ListViewModel {
viewModel(): AnyViewModel {
if (this.model instanceof ViewModel) return this.model;
if (this.model instanceof ListViewModel) return this.model;
if (this.model instanceof ServiceViewModel) return this.model;
throw Error(
"c-method: prop `model` is required, and must be a ViewModel or ListViewModel."
"c-method: prop `model` is required, and must be a ViewModel."
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
ObjectValue,
ApiStateTypeWithArgs,
ListViewModel,
ServiceViewModel,
} from "coalesce-vue";
import { ApiState, ViewModel } from "coalesce-vue";
import { computed, useAttrs } from "vue";
Expand Down Expand Up @@ -112,7 +113,12 @@ TModel extends Model ?
: undefined | string | ValueKind;

export type MethodForSpec<
TModel extends Model | ListViewModel | ViewModel | unknown = unknown,
TModel extends
| Model
| ServiceViewModel
| ListViewModel
| ViewModel
| unknown = unknown,
MethodKind extends Method = Method
> = "__never" extends keyof MethodsOf<TModel> // Check if we only know that the type's method names are any strings
? // If so, we have to allow any string because the exact method names aren't known.
Expand Down

0 comments on commit f733920

Please sign in to comment.