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:
@@ -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.
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
20
imports/ui/Assets.svelte
Normal 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
3694
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user