Skip to content

Commit

Permalink
fix: c-select-many-to-many - don't forcibly disable in possible bulkS…
Browse files Browse the repository at this point in the history
…ave usage scenarios.
  • Loading branch information
ascott18 committed Dec 22, 2023
1 parent f18a8c2 commit a1246a8
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 131 deletions.
1 change: 1 addition & 0 deletions playground/Coalesce.Web.Vue3/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

<v-btn variant="text" to="/">Home</v-btn>
<v-btn variant="text" to="/test">Test</v-btn>
<v-btn variant="text" to="/test-setup">Test2</v-btn>
<v-btn variant="text" to="/audit-logs">Audit</v-btn>
<v-btn variant="text" href="/coalesce-security">Security Overview</v-btn>

Expand Down
60 changes: 50 additions & 10 deletions playground/Coalesce.Web.Vue3/src/components/test-setup.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,70 @@
<template>
<v-container>
<v-btn @click="add" prepend-icon="fa fa-plus"> Add Product </v-btn>
<v-btn @click="vm.$bulkSave()" :loading="vm.$bulkSave.isLoading" prepend-icon="fa fa-save"> Save </v-btn>
<v-btn @click="vm.$load()" :loading="vm.$load.isLoading" prepend-icon="fa fa-sync"> Load </v-btn>
<v-btn
@click="vm.$bulkSave()"
:loading="vm.$bulkSave.isLoading"
prepend-icon="fa fa-save"
>
Save
</v-btn>
<v-btn
@click="vm.$load()"
:loading="vm.$load.isLoading"
prepend-icon="fa fa-sync"
>
Load
</v-btn>
<input
v-model="vm.caseKey"
:disabled="vm.caseKey && !vm.$getPropDirty('caseKey')"
placeholder="PK to load"
/>

<c-loader-status :loaders="{'': [vm.$bulkSave]}"></c-loader-status>
<c-loader-status :loaders="{ '': [vm.$bulkSave] }"></c-loader-status>
<h2>Case (pk: {{ vm.$primaryKey }})</h2>

<c-input :model="vm" for="title"></c-input>
<c-input :model="vm" for="caseProducts"></c-input>
<div v-for="x in vm.caseProducts">
<v-btn variant="text" size="x-small" @click="x.product?.$remove(); x.product=null; x.$remove()" icon="fa fa-trash"></v-btn>
<v-btn variant="text" size="x-small" @click="x.product?.$remove(); x.product=newProduct();" icon="fa fa-sync"></v-btn>
<v-btn
variant="text"
size="x-small"
@click="
x.product?.$remove();
x.product = null;
x.$remove();
"
icon="fa fa-trash"
></v-btn>
<v-btn
variant="text"
size="x-small"
@click="
x.product?.$remove();
x.product = newProduct();
"
icon="fa fa-sync"
></v-btn>
{{ x.product?.name }}: (pk: {{ x.$primaryKey }}, ref {{ x.$stableId }})

</div>
</v-container>
</template>

<script setup lang="ts">
import { CaseApiClient } from "@/api-clients.g";
import { CaseViewModel, PersonViewModel, ProductViewModel } from "@/viewmodels.g";
import {
CaseViewModel,
PersonViewModel,
ProductViewModel,
} from "@/viewmodels.g";
import { useBindToQueryString } from "coalesce-vue";
import { ref } from "vue";
// const vm = new CaseViewModel({title: 'asd'});
const vm = new CaseViewModel();
vm.$load(1);
vm.assignedTo = new PersonViewModel({ firstName: "bob", companyId: 1 });
// vm.$load(1);
vm.assignedTo = new PersonViewModel({ firstName: "bob", companyId: 1 });
vm.$bulkSave.setConcurrency("debounce");
async function add() {
Expand All @@ -39,7 +77,9 @@ async function del() {
}
function newProduct() {
return new ProductViewModel({ name: products[Math.ceil(Math.random() * products.length)-1] });
return new ProductViewModel({
name: products[Math.ceil(Math.random() * products.length) - 1],
});
}
const products = [
Expand Down
119 changes: 2 additions & 117 deletions playground/Coalesce.Web.Vue3/src/components/test.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,41 +67,6 @@
:src="caseVm.downloadImage.getResultObjectUrl()"
style="max-width: 100%"
/>

<c-admin-table :list="personList"></c-admin-table>

<!--<video v-if="caseVm.caseKey" :src="caseVm.downloadImage.getResultObjectUrl(this)" controls style="max-width: 100%">
</video>-->
<!--
<video v-if="caseVm.caseKey" :src="caseVm.downloadImage.url" controls style="max-width: 100%">
</video> -->
<v-form>
<c-input :model="caseVm" for="title"></c-input>
<c-input
:model="caseVm"
for="description"
textarea
placeholder="asdf"
></c-input>
<c-input :model="caseVm" for="openedAt"></c-input>
<c-input :model="caseVm" for="assignedTo" disabled></c-input>
<c-select :model="caseVm" for="assignedTo" readonly></c-select>
<c-select
for="Person"
v-model="caseVm.assignedTo"
placeholder="asdf"
></c-select>
<c-input :model="caseVm" for="reportedBy" placeholder="asdf"></c-input>
<c-input :model="caseVm" for="attachmentSize"></c-input>
<c-input :model="caseVm" for="severity"></c-input>
<c-input :model="caseVm" for="status"></c-input>
<c-input :model="caseVm" for="caseProducts"></c-input>
<c-display :model="caseVm" for="title" />
</v-form>
<v-text-field
v-model="caseVm.title"
label="vuetify direct"
></v-text-field>
</c-loader-status>
<!-- <c-input :model="person" for="height" /> -->
</v-container>
Expand Down Expand Up @@ -135,97 +100,17 @@ export default class Test extends Base {
date = null;
caseVm = new CaseViewModel();
pagination = {
sortBy: "",
page: 1,
rowsPerPage: 10,
descending: false,
};
count: number = 0;
search: string = "";
nextPage() {}
previousPage() {}
createMethods = {
getLabel(search: string, items: Person[]) {
const searchLower = search.toLowerCase();
if (items.some((a) => a.name?.toLowerCase().indexOf(searchLower) == 0)) {
return false;
}
return search;
},
async getItem(search: string, label: string) {
var vm = new PersonViewModel();
vm.firstName = label;
vm.height = 2;
vm.companyId = 3;
await vm.$save();
return vm;
},
};
async delete() {
console.log("delete");
}
get showProps() {
return Object.values(metadata.Person.props).filter(
(p) => p.role != "primaryKey" && p.role != "foreignKey"
);
}
get headers() {
return this.showProps.map((o) => ({ text: o.displayName, value: o.name }));
}
@Watch("pagination")
getData() {
this.isLoading = true;
new PersonApiClient()
.list({
page: this.pagination.page,
pageSize: this.pagination.rowsPerPage,
search: this.search,
orderBy: this.pagination.descending
? undefined
: this.pagination.sortBy,
orderByDescending: this.pagination.descending
? this.pagination.sortBy
: undefined,
})
.then((res) => {
const listResult = res.data;
const list = listResult.list;
this.isLoading = false;
if (!list) return;
this.items = list;
this.pagination.page = listResult.page ?? 0;
this.pagination.rowsPerPage = listResult.pageSize ?? 0;
this.count = listResult.totalCount ?? 0;
// this.person = new PersonViewModel(list[0]);
});
}
async created() {
this.personList.$params.noCount = true;
await this.caseVm.$load(15);
await this.caseVm.downloadImage(), this.caseVm.$startAutoSave(this);
await this.caseVm.downloadImage();
await this.company.$load(1);
//await this.person.$load(1);
}
async mounted() {
//new CaseViewModel({ caseKey: 1 }).uploadByteArray(new Uint8Array([60, 61, 62, 63]))
//new CaseViewModel({ caseKey: 1 }).uploadByteArray("abcd")
//var caller = this.person!.$apiClient.$makeCaller("item", c => c.changeSpacesToDashesInName(1));
//caller.result
//this.person.$startAutoSave(this, { wait: 0 })
}
async mounted() {}
items: models.Person[] = [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
:item-text="$attrs['item-text'] || itemText"
:item-value="itemValue"
:return-object="true"
:disabled="!modelPkValue"
:disabled="isDisabled"
no-filter
v-bind="inputBindAttrs"
>
Expand Down Expand Up @@ -84,6 +84,26 @@ export default defineComponent({
return model ? (model as any)[model.$metadata.keyProp.name] : null;
},
isDisabled() {
if (this.model instanceof ViewModel && this.model.$isAutoSaveEnabled) {
// If autosave is enabled (and therefore we're going to be calling
// APIs on the viewmodel automatically, we can only do so if we're able
// to populate the near-side foreign key on the join entity
// using the PK of the model we're bound to.
// This is not as precise a check as it could be, since if deep autosaves are enabled,
// once `this.model` gets saved then FKs will be fixed up and then the active unsaved
// will become valid and get saved too.
return this.modelPkValue == null;
} else {
// If not autosaving then we shouldn't force disabled
// since if bulkSaves are being used, bulkSaves can handle
// missing FK values as long as navigation properties are populated
// (which we do - see the `items` computed below.)
return false;
}
},
items() {
const items = this.listCaller.result || [];
const manyToManyMeta = this.manyToManyMeta;
Expand Down Expand Up @@ -284,7 +304,10 @@ export default defineComponent({
// @ts-expect-error internal state
vm._isRemoved = true;
// @ts-expect-error internal state
vm.$parent && (vm.$parent.$removedItems ??= []).push(vm);
if (vm.$parent) {
// @ts-expect-error internal state
(vm.$parent.$removedItems ??= []).push(vm);
}
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
:item-title="itemText"
:item-value="itemValue"
:return-object="true"
:disabled="!modelPkValue"
:disabled="isDisabled"
no-filter
v-bind="inputBindAttrs"
>
Expand Down Expand Up @@ -85,6 +85,26 @@ export default defineComponent({
return model ? (model as any)[model.$metadata.keyProp.name] : null;
},
isDisabled() {
if (this.model instanceof ViewModel && this.model.$isAutoSaveEnabled) {
// If autosave is enabled (and therefore we're going to be calling
// APIs on the viewmodel automatically, we can only do so if we're able
// to populate the near-side foreign key on the join entity
// using the PK of the model we're bound to.
// This is not as precise a check as it could be, since if deep autosaves are enabled,
// once `this.model` gets saved then FKs will be fixed up and then the active unsaved
// will become valid and get saved too.
return this.modelPkValue == null;
} else {
// If not autosaving then we shouldn't force disabled
// since if bulkSaves are being used, bulkSaves can handle
// missing FK values as long as navigation properties are populated
// (which we do - see the `items` computed below.)
return false;
}
},
items() {
const items = this.listCaller.result || [];
const manyToManyMeta = this.manyToManyMeta;
Expand Down Expand Up @@ -309,7 +329,10 @@ export default defineComponent({
// @ts-expect-error internal state
vm._isRemoved = true;
// @ts-expect-error internal state
vm.$parent && (vm.$parent.$removedItems ??= []).push(vm);
if (vm.$parent) {
// @ts-expect-error internal state
(vm.$parent.$removedItems ??= []).push(vm);
}
}
}
} else {
Expand Down

0 comments on commit a1246a8

Please sign in to comment.