Finished coding the AssetTypes part of the Admin page. Tested adding assets. Did not implement removing them or updating them. Added the start for a page to manage assets.

This commit is contained in:
2022-06-29 00:31:47 -07:00
parent 3c58f3f8da
commit 94c7fb9f7b
5 changed files with 3734 additions and 75 deletions

View File

@@ -22,13 +22,7 @@ const AssetTypesSchema = new SimpleSchema({
label: "Description", label: "Description",
optional: true, optional: true,
trim: true, trim: true,
defaultValue: "" defaultValue: "",
},
hasSerial: {
type: Boolean,
label: "Is a serial number available for all instances?",
optional: false,
defaultValue: false
}, },
}); });
@@ -37,9 +31,9 @@ AssetTypes.attachSchema(AssetTypesSchema);
if (Meteor.isServer) { if (Meteor.isServer) {
// Drop any old indexes we no longer will use. Create indexes we need. // Drop any old indexes we no longer will use. Create indexes we need.
try {AssetTypes._dropIndex("name")} catch(e) {} try {AssetTypes._dropIndex("External ID")} catch(e) {}
//AssetTypes.createIndex({name: "text"}, {name: "name", unique: false}); //AssetTypes.createIndex({name: "text"}, {name: "name", unique: false});
AssetTypes.createIndex({id: 1}, {name: "External ID", unique: true}); //AssetTypes.createIndex({id: 1}, {name: "External ID", unique: true});
//Debug: Show all indexes. //Debug: Show all indexes.
// AssetTypes.rawCollection().indexes((err, indexes) => { // AssetTypes.rawCollection().indexes((err, indexes) => {
@@ -52,20 +46,28 @@ if (Meteor.isServer) {
}); });
} }
Meteor.methods({ Meteor.methods({
'assetTypes.add'(name, description, hasSerial) { 'assetTypes.add'(name, description) {
check(name, String); check(name, String);
check(description, String); check(description, String);
check(hasSerial, Boolean);
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
AssetTypes.insert({name, description, hasSerial}); AssetTypes.insert({name, description});
}
},
'assetTypes.update'(_id, name, description) {
check(_id, String);
check(name, String);
check(description, String);
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
AssetTypes.update({_id}, {$set: {name, description}});
} }
}, },
'assetTypes.remove'(_id) { 'assetTypes.remove'(_id) {
check(_id, String); check(_id, String);
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
//TODO: Need to first verify there are no checked out assets to the staff member. //TODO: Need to either remove all assets of this type, or change their type.
} }
}, },
}); });

View File

@@ -15,7 +15,8 @@
Meteor.subscribe('assetTypes'); Meteor.subscribe('assetTypes');
}); });
const fixRecords = () => {Meteor.call("admin.fixRecords");} // Should not be needed now. Did not work well - had a bug somewhere.
// const fixRecords = () => {Meteor.call("admin.fixRecords");}
const siteColumns = [ const siteColumns = [
{ {
@@ -54,7 +55,6 @@
editedSite.subscribe(site => {dirtySite = Object.assign({name: ""}, site)}); editedSite.subscribe(site => {dirtySite = Object.assign({name: ""}, site)});
// Load the sites (reactive). // Load the sites (reactive).
let sites = Sites.find({}); let sites = Sites.find({});
const applySiteChanges = () => { const applySiteChanges = () => {
if(dirtySite._id) if(dirtySite._id)
Meteor.call("sites.update", dirtySite._id, dirtySite.name); Meteor.call("sites.update", dirtySite._id, dirtySite.name);
@@ -66,6 +66,7 @@
editedSite.set(null); editedSite.set(null);
} }
let selectedSite = null; let selectedSite = null;
let students = null; let students = null;
let staff = null; let staff = null;
$: { $: {
@@ -199,27 +200,43 @@
minWidth: 100, minWidth: 100,
weight: 1, weight: 1,
cls: "description", cls: "description",
}, {
key: "hasSerial",
title: "Has Serial",
value: v => v.hasSerial,
minWidth: 100,
weight: 1,
cls: "hasSerial",
}, },
]; ];
const assetTypesActions = {
title: "Actions",
headerWidgets: [
{icon: "add_box", action: () => {editedAssetType.set({name: ""});}, tooltip: "Add a new asset type."}
],
rowWidgets: [
{icon: "add_circle", action: (v) => {editedAssetType.set(v)}},
{icon: "delete", action: (v) => {deleteAssetType(v)}}
],
};
let editedAssetType = writable(null); let editedAssetType = writable(null);
const onAssetTypeSelection = (e) => { const onAssetTypeSelection = (e) => {
} }
let dirtyAssetType = null; let dirtyAssetType = null;
// Copy the edited site when ever it changes, set some defaults for a new site object (to make the view happy). // Copy the edited value when ever it changes, set some defaults for a new value object (to make the view happy).
editedAssetType.subscribe(v => {dirtyAssetType = Object.assign({name: ""}, v)}); editedAssetType.subscribe(v => {dirtyAssetType = Object.assign({name: "", description: ""}, v)});
// Load the sites (reactive). // Load the sites (reactive).
let assetTypes = AssetTypes.find({}); let assetTypes = AssetTypes.find({});
const deleteAssetType = assetType => {
//TODO:
};
const applyAssetTypeChanges = () => {
if(dirtyAssetType._id)
Meteor.call("assetTypes.update", dirtyAssetType._id, dirtyAssetType.name, dirtyAssetType.description);
else
Meteor.call("assetTypes.add", dirtyAssetType.name, dirtyAssetType.description);
editedAssetType.set(null);
}
const rejectAssetTypeChanges = () => {
editedSite.set(null);
}
</script> </script>
<div class="container"> <div class="container">
<h2>Sites</h2>
<GridTable bind:rows={sites} columns="{siteColumns}" actions="{actions}" rowKey="{(v) => {return v._id}}" bind:edited="{editedSite}" on:selection={onSiteSelection}> <GridTable bind:rows={sites} columns="{siteColumns}" actions="{actions}" rowKey="{(v) => {return v._id}}" bind:edited="{editedSite}" on:selection={onSiteSelection}>
{#if dirtySite} {#if dirtySite}
<div class="editorContainer"> <div class="editorContainer">
@@ -286,21 +303,20 @@
{/if} {/if}
<h2>Asset Types</h2> <h2>Asset Types</h2>
<GridTable bind:rows={assetTypes} columns="{assetTypesColumns}" actions="{null}" rowKey="{(v) => {return v._id}}" bind:edited="{editedAssetType}" on:selection={onAssetTypeSelection}> <GridTable bind:rows={assetTypes} columns="{assetTypesColumns}" actions="{assetTypesActions}" rowKey="{(v) => {return v._id}}" bind:edited="{editedAssetType}" on:selection={onAssetTypeSelection}>
{#if dirtySite} {#if dirtyAssetType}
<div class="editorContainer"> <div class="editorContainer">
<div style="grid-column: 1/span 1"> <div style="grid-column: 1/span 1">
<TextField type="text" style="width: 100%" bind:value={dirtySite.name} label="Name"> <TextField type="text" style="width: 100%" bind:value={dirtyAssetType.name} label="Name">
<HelperText slot="helper">Provide a unique name for the site.</HelperText> <HelperText slot="helper">Provide a unique name for the asset type.</HelperText>
</TextField>
<TextField type="text" style="width: 100%" bind:value={dirtyAssetType.description} label="Description">
<HelperText slot="helper">A detailed description.</HelperText>
</TextField> </TextField>
</div> </div>
<button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applySiteChanges}> <button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applyAssetTypeChanges}>check</button>
check <button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectAssetTypeChanges}>close</button>
</button>
<button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectSiteChanges}>
close
</button>
</div> </div>
{/if} {/if}
</GridTable> </GridTable>

View File

@@ -8,6 +8,7 @@
import Users from './Users.svelte'; import Users from './Users.svelte';
import Admin from './Admin.svelte'; import Admin from './Admin.svelte';
import Announcer from './Announcer.svelte'; import Announcer from './Announcer.svelte';
import Assets from "./Assets.svelte";
// When the URL changes, run the code... in this case to scroll to the top. // When the URL changes, run the code... in this case to scroll to the top.
router.subscribe(_ => window.scrollTo(0, 0)); router.subscribe(_ => window.scrollTo(0, 0));
@@ -66,6 +67,7 @@
<a href="/users">Users</a> <a href="/users">Users</a>
{/if} {/if}
{#if isAdmin} {#if isAdmin}
<a href="/assets">Assets</a>
<a href="/admin">Admin</a> <a href="/admin">Admin</a>
{/if} {/if}
</nav> </nav>
@@ -79,6 +81,11 @@
</div> </div>
</div> </div>
</Route> </Route>
<Route path="/assets">
{#if isAdmin}
<Assets/>
{/if}
</Route>
<Route path="/admin"> <Route path="/admin">
{#if isAdmin} {#if isAdmin}
<Admin/> <Admin/>

20
imports/ui/Assets.svelte Normal file
View File

@@ -0,0 +1,20 @@
<script>
import {Meteor} from "meteor/meteor";
import {onMount} from "svelte";
import {writable} from "svelte/store";
import TextField from '@smui/textfield';
import HelperText from '@smui/textfield/helper-text';
import {AssetTypes} from "../api/asset-types";
import {Assets} from "../api/assets";
onMount(async () => {
Meteor.subscribe('assetTypes');
});
</script>
<div class="container">
</div>
<style>
</style>

3694
package-lock.json generated

File diff suppressed because it is too large Load Diff