Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • maspect/amiv-admintool
  • emustafa/amiv-admintool
  • dvruette/amiv-admintool
  • amiv/amiv-admintool
4 results
Show changes
import m from 'mithril';
import { Card, Toolbar, ToolbarTitle, Button, Snackbar } from 'polythene-mithril';
import { ListSelect, DatalistController, Chip } from 'amiv-web-ui-components';
import ItemView from '../views/itemView';
import TableView from '../views/tableView';
import RelationlistController from '../relationlistcontroller';
import { ResourceHandler } from '../auth';
import { icons, Property } from '../views/elements';
import { colors } from '../style';
export default class UserView extends ItemView {
constructor(vnode) {
super(vnode);
// a controller to handle the groupmemberships of this user
this.groupmemberships = new RelationlistController({
primary: 'groupmemberships', secondary: 'groups', query: { where: { user: this.data._id } },
});
// a controller to handle the eventsignups of this user
this.eventsignups = new RelationlistController({
primary: 'eventsignups', secondary: 'events', query: { where: { user: this.data._id } },
});
// initially, don't display the choice field for a new group
// (this will be displayed once the user clicks on 'new')
this.groupchoice = false;
// a controller to handle the list of possible groups to join
this.groupHandler = new ResourceHandler('groups', ['name']);
this.groupController = new DatalistController(
(query, search) => this.groupHandler.get({ search, ...query }),
);
// exclude the groups where the user is already a member
this.groupmemberships.handler.get({ where: { user: this.data._id } })
.then((data) => {
const groupIds = data._items.map(item => item.group);
this.groupController.setQuery({
where: { _id: { $nin: groupIds } },
});
});
this.sessionsHandler = new ResourceHandler('sessions');
}
oninit() {
this.groupmemberships.refresh();
}
view() {
const stdMargin = { margin: '5px' };
let membership = m(Chip, {
svg: icons.clear,
svgBackground: colors.amiv_red,
style: stdMargin,
}, 'No Member');
if (this.data.membership === 'regular') {
membership = m(Chip, {
svg: icons.checked,
svgBackground: colors.green,
style: stdMargin,
}, 'Regular Member');
} else if (this.data.membership === 'extraordinary') {
membership = m(Chip, {
svg: icons.checked,
svgBackground: colors.green,
style: stdMargin,
}, 'Extraordinary Member');
} else if (this.data.membership === 'honorary') {
membership = m(Chip, {
svg: icons.star,
svgBackground: colors.orange,
style: stdMargin,
}, 'Honorary Member');
}
// Selector that is only displayed if "new" is clicked in the
// groupmemberships. Selects a group to request membership for.
const groupSelect = m(ListSelect, {
controller: this.groupController,
listTileAttrs: group => Object.assign({}, { title: group.name }),
selectedText: group => group.name,
onSubmit: (group) => {
this.groupchoice = false;
this.groupmemberships.handler.post({
user: this.data._id,
group: group._id,
}).then(() => {
this.groupmemberships.refresh();
m.redraw();
});
},
onCancel: () => { this.groupchoice = false; m.redraw(); },
});
const now = new Date();
return this.layout([
m('div.maincontainer', [
m('h1', `${this.data.firstname} ${this.data.lastname}`),
membership,
this.data.department && m(
Chip,
{ svg: icons.department, style: stdMargin },
this.data.department,
),
m(Chip, {
svg: this.data.send_newsletter ? icons.checked : icons.clear,
style: stdMargin,
}, 'newsletter'),
m('div', { style: { display: 'flex' } }, [
this.data.nethz && m(Property, { title: 'NETHZ', style: stdMargin }, this.data.nethz),
this.data.email && m(Property, { title: 'Email', style: stdMargin }, this.data.email),
m(Property, { title: 'Legi', style: stdMargin }, this.data.legi ? this.data.legi : '-'),
m(Property, { title: 'RFID', style: stdMargin }, this.data.rfid ? this.data.rfid : '-'),
this.data.phone && m(Property, { title: 'Phone', style: stdMargin }, this.data.phone),
]),
]),
m('div.viewcontainer', [
m('div.viewcontainercolumn', m(Card, {
style: { height: '350px' },
content: m('div', [
m(Toolbar, { compact: true }, [
m(ToolbarTitle, { text: 'Event Signups' }),
]),
m(TableView, {
tableHeight: '175px',
controller: this.eventsignups,
tileContent: item => m('div', item.event.title_en || item.event.title_de),
titles: ['Event'],
clickOnRows: (data) => { m.route.set(`/events/${data.event._id}`); },
filters: [[{
name: 'upcoming',
query: { 'event.time_start': { $gte: `${now.toISOString().slice(0, -5)}Z` } },
}, {
name: 'past',
query: { 'event.time_start': { $lt: `${now.toISOString().slice(0, -5)}Z` } },
}]],
// per default, enable the 'upcoming' filter
initFilterIdxs: [[0, 0]],
}),
]),
})),
m('div.viewcontainercolumn', m(Card, {
style: { height: '350px' },
content: m('div', [
this.groupchoice && groupSelect,
m(Toolbar, { compact: true }, [
m(ToolbarTitle, { text: 'Group Memberships' }),
m(Button, {
className: 'blue-button',
label: 'add',
events: { onclick: () => { this.groupchoice = true; } },
}),
]),
m(TableView, {
tableHeight: '225px',
controller: this.groupmemberships,
keys: ['group.name', 'expiry'],
titles: ['Group Name', 'Expires'],
clickOnRows: (data) => { m.route.set(`/groups/${data.group._id}`); },
}),
]),
})),
]),
], [
m(Button, {
label: 'log out all Sessions',
className: 'itemView-delete-button',
border: true,
events: {
onclick: () => {
this.sessionsHandler.get({
where: { user: this.data._id },
}).then((response) => {
if (response._items.length === 0) {
Snackbar.show({ title: 'No active sessions for this user.' });
} else {
response._items.forEach((session) => {
this.sessionsHandler.delete(session);
});
}
});
},
},
}),
]);
}
}
// as taken from underscore:
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
export function debounce(func, wait, immediate) {
let timeout;
return function outer(...args) {
const context = this;
function later() {
timeout = null;
if (!immediate) func.apply(context, args);
}
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
export function dateFormatter(datestring, time = true) {
// converts an API datestring into the standard format 01.01.1990, 10:21
if (!datestring) return '';
const date = new Date(datestring);
if (!time) return date.toLocaleDateString('de-DE');
return date.toLocaleString('de-DE', {
day: '2-digit',
month: '2-digit',
year: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
}
import m from 'mithril';
import { IconButton, Toolbar, ToolbarTitle, Button } from 'polythene-mithril';
import { Form } from 'amiv-web-ui-components';
import ItemView from './itemView';
import { icons } from './elements';
import { colors } from '../style';
export default class EditView extends ItemView {
/**
* Extension of ItemView to edit a data item
*
* Requires:
* - call constructor with vnode, resource, (valid, false by default)
* - vnode.attrs.onfinish has to be a callback function that is called after
* the edit is finished
* @param {object} vnode [as provided by mithril]
* @param {string} resource [the API resource of this view, e.g. 'events']
* @param {object} embedded [any embedding query that should be added
* to API requests for this resource]
*/
constructor(vnode) {
super(vnode);
// the form is valid in case that the item controller is in edit mode
const validInitially = this.controller.modus === 'edit';
// start a form to collect the submit data
this.form = new Form({}, validInitially, 4, Object.assign({}, this.controller.data));
this.form.setSchema(JSON.parse(JSON.stringify(this.handler.schema)));
}
/**
* Submit the changed version of this.data
*
* @param {Boolean} true if the data should be send as FormData instead of
* JSON. Necessary in cases where files are included in the
* changes.
*/
submit(data) {
return new Promise((resolve, reject) => {
let request;
if (this.controller.modus === 'edit') {
// this is a patch to an existing item
request = this.controller.patch(data);
} else {
request = this.controller.post(data);
}
request.then((response) => {
resolve(response);
}).catch((error) => {
// Process the API error
if ('_issues' in error) {
// there are problems with some fields, display them
Object.keys(error._issues).forEach((field) => {
this.form.errors[field] = [error._issues[field]];
this.form.valid = false;
});
// eslint-disable-next-line no-console
console.log(this.form.errors);
m.redraw();
reject(error);
} else {
// eslint-disable-next-line no-console
console.log(error);
}
});
});
}
beforeSubmit() {
if (Object.keys(this.form.data).length > 0) {
this.submit(this.form.data).then(() => this.controller.changeModus('view'));
} else {
this.controller.changeModus('view');
}
}
layout(children, buttonLabel = 'submit', wrapInContainer = true) {
return m('div', { style: { 'background-color': 'white' } }, [
m(Toolbar, { style: { 'background-color': colors.orange } }, [
m(IconButton, {
icon: { svg: { content: m.trust(icons.clear) } },
events: { onclick: () => { this.controller.cancel(); } },
}),
m(ToolbarTitle, `${((this.controller.modus === 'new') ? 'New' : 'Edit')}`
+ ` ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`),
m(Button, {
className: 'blue-button-filled',
extraWide: true,
label: buttonLabel,
// NOTE: Temporary fix as the `valid` flag of the `Form` instance does
// not work reliably. This ensures that the form can be submitted.
// disabled: !this.form.valid,
events: { onclick: () => { this.beforeSubmit(); } },
}),
]),
...!this.form.schema ? [''] : [
wrapInContainer && m('div.maincontainer', {
style: { height: 'calc(100vh - 130px)', 'overflow-y': 'scroll', padding: '10px' },
}, children),
!wrapInContainer && children,
],
]);
}
}
import m from 'mithril';
import { Chip } from 'amiv-web-ui-components';
export const icons = {
search: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>',
back: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>',
clear: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',
ArrowRight: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/><path d="M0-.25h24v24H0z" fill="none"/></svg>',
ArrowDown: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z"/><path d="M0-.75h24v24H0z" fill="none"/></svg>',
iconUsersSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
iconEventSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
iconJobsSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"/></svg>',
ArrowLeft: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/><path d="M0-.5h24v24H0z" fill="none"/></svg>',
checked: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>',
group: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>',
cloud: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></svg>',
star: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
email: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
department: '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 14V6H4v36h40V14H24zM12 38H8v-4h4v4zm0-8H8v-4h4v4zm0-8H8v-4h4v4zm0-8H8v-4h4v4zm8 24h-4v-4h4v4zm0-8h-4v-4h4v4zm0-8h-4v-4h4v4zm0-8h-4v-4h4v4zm20 24H24v-4h4v-4h-4v-4h4v-4h-4v-4h16v20zm-4-16h-4v4h4v-4zm0 8h-4v4h4v-4z"/></svg>',
amivWheel: '<svg width="81.059502" height="80.056625" viewBox="0 0 82 82" id="svg2"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath18"><path d="m 0,849.563 1960.52,0 L 1960.52,0 0,0 0,849.563 z" id="path20" /></clipPath></defs><g transform="matrix(1.25,0,0,-1.25,-16.34525,92.96925)" id="g10"><g transform="scale(0.1,0.1)" id="g12"><g clip-path="url(#clipPath18)" id="g16"><path d="m 566.012,342.883 c -44.453,-61.184 -130.383,-74.797 -191.563,-30.344 -3.969,2.891 -7.719,5.957 -11.289,9.18 l 41.192,29.922 40.945,-56.375 51.351,117.707 37.684,-51.848 44.727,32.5 -40.387,55.598 41.469,30.132 c 19.257,-43.32 15.679,-95.437 -14.129,-136.472 m -235.504,23.465 c -19.887,43.554 -16.5,96.32 13.601,137.75 44.45,61.179 130.383,74.789 191.559,30.336 4.352,-3.161 8.391,-6.579 12.254,-10.125 l -41.762,-30.344 -40.558,55.82 -44.735,-32.5 40.563,-55.828 -0.067,-0.051 -127.726,-12.449 38.203,-52.578 -41.332,-30.031 z m 366.523,24.668 c 1.41,10.644 2.207,21.48 2.207,32.511 0,11.028 -0.797,21.86 -2.207,32.508 l -57.468,8.922 c -2.571,11.469 -6.196,22.711 -10.864,33.57 l 41.211,40.961 c -5.109,9.438 -10.828,18.676 -17.312,27.598 -6.481,8.922 -13.496,17.223 -20.899,25 l -51.679,-26.52 c -4.372,3.84 -8.93,7.532 -13.731,11.02 -4.84,3.512 -9.801,6.73 -14.84,9.719 l 9.258,57.351 c -9.676,4.641 -19.734,8.75 -30.238,12.16 -10.481,3.407 -21.039,5.993 -31.586,7.938 l -26.262,-51.918 c -11.742,1.07 -23.519,1.031 -35.199,-0.066 l -26.293,51.984 c -10.559,-1.945 -21.109,-4.531 -31.598,-7.938 -10.492,-3.41 -20.551,-7.519 -30.23,-12.148 l 9.269,-57.434 c -10.039,-5.925 -19.582,-12.859 -28.511,-20.707 l -51.746,26.559 c -7.407,-7.777 -14.422,-16.07 -20.903,-25 -6.492,-8.922 -12.211,-18.16 -17.32,-27.598 l 41.258,-41.011 c -4.715,-10.922 -8.36,-22.137 -10.887,-33.512 l -57.481,-8.93 c -1.421,-10.64 -2.218,-21.48 -2.218,-32.508 0,-11.031 0.797,-21.855 2.218,-32.511 l 57.563,-8.934 c 2.559,-11.445 6.168,-22.668 10.82,-33.496 L 240.09,307.57 c 5.109,-9.445 10.828,-18.683 17.32,-27.597 6.481,-8.926 13.488,-17.227 20.903,-25 l 51.675,26.523 c 4.41,-3.867 9,-7.59 13.84,-11.105 4.801,-3.485 9.723,-6.688 14.723,-9.657 l -9.258,-57.336 c 9.687,-4.636 19.746,-8.75 30.238,-12.156 10.489,-3.418 21.039,-5.996 31.598,-7.929 l 26.219,51.843 c 11.773,-1.093 23.57,-1.062 35.285,0.039 l 26.238,-51.894 c 10.559,1.945 21.117,4.523 31.598,7.941 10.504,3.406 20.551,7.52 30.238,12.149 l -9.246,57.285 c 10.078,5.957 19.648,12.898 28.617,20.789 l 51.621,-26.492 c 7.403,7.773 14.41,16.074 20.899,25 6.484,8.914 12.203,18.152 17.312,27.597 l -41.148,40.907 c 4.73,10.957 8.379,22.207 10.929,33.644 l 57.34,8.895" id="path30" style="fill:#f03d30;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></svg>',
menu: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>',
studydoc: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></svg>',
blacklist: '<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="#000000" d="M22.5,2.09C21.6,3 20.13,3.73 18.31,4.25C16.59,2.84 14.39,2 12,2C9.61,2 7.41,2.84 5.69,4.25C3.87,3.73 2.4,3 1.5,2.09C1.53,3.72 2.35,5.21 3.72,6.4C2.63,8 2,9.92 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,9.92 21.37,8 20.28,6.4C21.65,5.21 22.47,3.72 22.5,2.09M7.5,8.5L10.5,10C10.5,10.8 9.8,11.5 9,11.5C8.2,11.5 7.5,10.8 7.5,10V8.5M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23M16.5,10C16.5,10.8 15.8,11.5 15,11.5C14.2,11.5 13.5,10.8 13.5,10L16.5,8.5V10Z" /></svg>',
error: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>',
sortingArrow: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
};
// Property as specified by material design: small, grey title and larger
// darker content text below
// attrs is the title, children the text
// therefore, you can call it with m(Property, title, text)
export class Property {
view({ attrs: { title, leftAlign = true, ...restAttrs }, children }) {
return m('div', { style: { margin: '5px' }, ...restAttrs }, [
m('span', {
style: {
'margin-top': '10px',
'margin-bottom': '3px',
color: 'rgba(0, 0, 0, 0.54)',
},
}, m.trust(title)),
m('p', {
style: {
color: 'rgba(0, 0, 0, 0.87)',
'text-align': leftAlign ? 'left' : 'right',
},
}, children),
]);
}
}
export class selectGroup {
view(vnode) {
return m('div.form-group', { class: vnode.attrs.classes }, [
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m(
`select[name=${vnode.attrs.name}][id=${vnode.attrs.name}].form-control`,
{ value: vnode.attrs.value, onchange: vnode.attrs.onchange },
vnode.attrs.options.map(option => m('option', option)),
),
]);
}
}
export class submitButton {
view({ attrs: { args, active, text } }) {
const argsCopy = args;
if (!active) {
argsCopy.disabled = 'disabled';
}
return m('div.btn', argsCopy, text);
}
}
export class FilterChip {
view({ attrs: { selected = false, onclick = () => { } }, children }) {
return m(Chip, {
'margin-left': '5px',
'margin-right': '5px',
background: selected ? '#aaaaaa' : '#dddddd',
svgBackground: '#aaaaaa',
textColor: selected ? '#000000' : '#999999',
svgColor: '#000000',
svg: selected ? icons.checked : null,
onclick,
onClick: onclick,
}, children);
}
}
import m from 'mithril';
import { IconButton, Toolbar, Dialog, Button } from 'polythene-mithril';
import { ButtonCSS } from 'polythene-css';
import { colors } from '../style';
import { loadingScreen } from '../layout';
import { icons } from './elements';
ButtonCSS.addStyle('.itemView-edit-button', {
color_light_background: colors.light_blue,
color_light_text: 'white',
});
ButtonCSS.addStyle('.itemView-delete-button', {
color_light_text: colors.amiv_red,
color_light_border: colors.amiv_red,
});
export default class ItemView {
/* Basic class to show a data item
*
* Required:
* - gets attribute 'controller' when rendered
*/
constructor({ attrs: { controller, onDelete } }) {
this.controller = controller;
this.handler = this.controller.handler;
this.data = this.controller.data;
this.resource = this.controller.resource;
if (!onDelete) this.onDelete = () => { m.route.set(`/${controller.resource}`); };
else this.onDelete = onDelete;
}
delete() {
Dialog.show({
body: 'Are you sure you want to delete this item?',
backdrop: true,
footerButtons: [
m(Button, {
label: 'Cancel',
events: { onclick: () => Dialog.hide() },
}),
m(Button, {
label: 'Delete',
events: {
onclick: () => {
Dialog.hide();
this.controller.handler.delete(this.data).then(this.onDelete);
},
},
})],
});
}
layout(children, buttons = []) {
if (!this.controller || !this.controller.data) return m(loadingScreen);
// update the data reference
this.data = this.controller.data;
return m('div', [
m(Toolbar, [
this.data._links.self.methods.indexOf('PATCH') > -1 && m('div', {
style: { width: 'calc(100% - 48px)' },
}, m('div.pe-button-row', [
m(Button, {
element: 'div',
className: 'itemView-edit-button',
label: `Edit ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`,
events: { onclick: () => { this.controller.changeModus('edit'); } },
}),
m(Button, {
label: `Delete ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`,
className: 'itemView-delete-button',
border: true,
events: { onclick: () => this.delete() },
}),
...buttons,
])),
m(IconButton, {
style: { 'margin-left': 'auto', 'margin-right': '0px' },
icon: { svg: { content: m.trust(icons.clear) } },
events: { onclick: () => { this.controller.cancel(); } },
}),
]),
m('div', {
style: { height: 'calc(100vh - 130px)', 'overflow-y': 'scroll' },
}, children),
]);
}
}
This diff is collapsed.
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove local server and code map
config.devServer = undefined;
//config.devtool = '';
config.mode = 'production';
config.optimization = {
usedExports: true,
sideEffects: true,
splitChunks: {
chunks: 'async', // TODO possibly set to all
automaticNameDelimiter: '-',
name: true,
},
};
// Add optimization plugins
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
);
// Replace local with development server config
config.resolve.alias.networkConfig = `${__dirname}/src/networkConfig.dev.json`;
module.exports = config;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.