🔥 Cleanups

- Remove unused files
- Remove usage of lodash, query-string and momentjs
- Don't bundle svg and eot fonts from fontawesome
This commit is contained in:
nikolark committed 2020-01-05 17:21:19 +01:00
1 parent a94bbed03b
commit 77d7d0af99
22 files changed
+204 -976

No files matched your search

-107
View File
@@ -1,107 +0,0 @@
'use strict';
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;
gulp.task('styles', function () {
return gulp.src('app/styles/main.scss')
.pipe($.sass({
includePaths: ['.'],
sourceComments: 'map'
}).on('error', $.sass.logError))
.pipe($.autoprefixer('last 1 version'))
.pipe(gulp.dest('dist/styles'))
.pipe(browserSync.stream());
});
gulp.task('scripts', function () {
return gulp.src('app/scripts/**/*.js')
.pipe($.jshint())
.pipe($.jshint.reporter(require('jshint-stylish')))
.pipe(gulp.dest('dist/scripts'))
});
gulp.task('vendorscripts', function() {
var vendorScripts = [
'node_modules/jquery/dist/jquery.min.js',
'node_modules/underscore/underscore-min.js',
'node_modules/nunjucks/browser/nunjucks-slim.min.js',
'node_modules/moment/min/moment.min.js',
'node_modules/moment/locale/nb.js',
'node_modules/bootstrap-sass/assets/javascripts/bootstrap/alert.js',
'node_modules/bootstrap-sass/assets/javascripts/bootstrap/dropdown.js',
'node_modules/bootstrap-sass/assets/javascripts/bootstrap/collapse.js',
'node_modules/pnotify/dist/pnotify.js',
'node_modules/query-string/query-string.js'
];
return gulp.src(vendorScripts)
.pipe($.concat('vendor.js'))
.pipe(gulp.dest('dist/scripts'));
});
gulp.task('images', function () {
return gulp.src('app/images/**/*')
.pipe($.imagemin({
optimizationLevel: 3,
progressive: true,
interlaced: true
}))
.pipe(gulp.dest('dist/images'))
});
gulp.task('fonts', function () {
return gulp.src(['node_modules/bootstrap-sass/assets/fonts/**/*'])
.pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
.pipe($.flatten())
.pipe(gulp.dest('dist/fonts'))
});
gulp.task('templates', function () {
return gulp.src('app/templates/*.html')
.pipe($.nunjucks())
.pipe($.concat('templates.js'))
.pipe(gulp.dest('dist/scripts'))
});
gulp.task('extras', function () {
return gulp.src(['app/*.*', '!app/*.html', '!app/templates/*.html', '!app/styles/*.scss'], { dot: true })
.pipe(gulp.dest('dist'));
});
gulp.task('clean', del.bind(null, ['dist']));
gulp.task('build', ['styles', 'scripts', 'vendorscripts', 'templates', 'images', 'fonts', 'extras'],
function() {
return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
}
);
gulp.task('default', ['clean'], function () {
gulp.start('build');
});
gulp.task('serve', ['styles', 'scripts'], function () {
require('opn')('http://localhost:3000');
});
gulp.task('watch', ['serve'], function () {
browserSync.init({
proxy: 'localhost:8000'
});
// watch for changes
gulp.watch([
'../../templates/**/*.html',
'app/templates/*.html',
'dist/scripts/**/*.js',
'dist/images/**/*'
]).on('change', reload);
gulp.watch('app/styles/**/*.scss', ['styles']);
gulp.watch('app/scripts/**/*.js', ['scripts']);
gulp.watch('app/images/**/*', ['images']);
gulp.watch('app/templates/**/*.html', ['templates']);
});
+4 -27
View File
@@ -3357,7 +3357,8 @@
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
"dev": true
},
"deep-equal": {
"version": "1.1.1",
@@ -7289,7 +7290,8 @@
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"lodash.isfinite": {
"version": "3.3.2",
@@ -7684,11 +7686,6 @@
}
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -9603,16 +9600,6 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz",
"integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA=="
},
"query-string": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.9.0.tgz",
"integrity": "sha512-KG4bhCFYapExLsUHrFt+kQVEegF2agm4cpF/VNc6pZVthIfCc/GK8t8VyNIE3nyXG9DK3Tf2EGkxjR6/uRdYsA==",
"requires": {
"decode-uri-component": "^0.2.0",
"split-on-first": "^1.0.0",
"strict-uri-encode": "^2.0.0"
}
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
@@ -11066,11 +11053,6 @@
}
}
},
"split-on-first": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
},
"split-string": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -11214,11 +11196,6 @@
"limiter": "^1.0.5"
}
},
"strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-3
View File
@@ -23,12 +23,9 @@
"graphql-anywhere": "^4.2.6",
"graphql-tag": "^2.10.1",
"jquery": "^3.4.1",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"pnotify": "^4.0.0",
"popper.js": "^1.16.0",
"qs": "^6.9.1",
"query-string": "^6.9.0",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
@@ -1,112 +0,0 @@
/*
Author : Hunter Perrin
Version : 3.0.0
Link : http://sciactive.com/pnotify/
*/
/* -- Notice */
.ui-pnotify {
top: 36px;
right: 36px;
position: absolute;
height: auto;
z-index: 2;
}
body > .ui-pnotify {
/* Notices in the body context should be fixed to the viewport. */
position: fixed;
/* Ensures notices are above everything */
z-index: 100040;
}
.ui-pnotify-modal-overlay {
background-color: rgba(0, 0, 0, .4);
top: 0;
left: 0;
position: absolute;
height: 100%;
width: 100%;
z-index: 1;
}
body > .ui-pnotify-modal-overlay {
position: fixed;
z-index: 100039;
}
.ui-pnotify.ui-pnotify-in {
display: block !important;
}
.ui-pnotify.ui-pnotify-move {
transition: left .5s ease, top .5s ease, right .5s ease, bottom .5s ease;
}
.ui-pnotify.ui-pnotify-fade-slow {
transition: opacity .6s linear;
opacity: 0;
}
.ui-pnotify.ui-pnotify-fade-slow.ui-pnotify.ui-pnotify-move {
transition: opacity .6s linear, left .5s ease, top .5s ease, right .5s ease, bottom .5s ease;
}
.ui-pnotify.ui-pnotify-fade-normal {
transition: opacity .4s linear;
opacity: 0;
}
.ui-pnotify.ui-pnotify-fade-normal.ui-pnotify.ui-pnotify-move {
transition: opacity .4s linear, left .5s ease, top .5s ease, right .5s ease, bottom .5s ease;
}
.ui-pnotify.ui-pnotify-fade-fast {
transition: opacity .2s linear;
opacity: 0;
}
.ui-pnotify.ui-pnotify-fade-fast.ui-pnotify.ui-pnotify-move {
transition: opacity .2s linear, left .5s ease, top .5s ease, right .5s ease, bottom .5s ease;
}
.ui-pnotify.ui-pnotify-fade-in {
opacity: 1;
}
.ui-pnotify .ui-pnotify-shadow {
-webkit-box-shadow: 0px 6px 28px 0px rgba(0,0,0,0.1);
-moz-box-shadow: 0px 6px 28px 0px rgba(0,0,0,0.1);
box-shadow: 0px 6px 28px 0px rgba(0,0,0,0.1);
}
.ui-pnotify-container {
background-position: 0 0;
padding: .8em;
height: 100%;
margin: 0;
}
.ui-pnotify-container:after {
content: " "; /* Older browser do not support empty content */
visibility: hidden;
display: block;
height: 0;
clear: both;
}
.ui-pnotify-container.ui-pnotify-sharp {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.ui-pnotify-title {
display: block;
margin-bottom: .4em;
margin-top: 0;
}
.ui-pnotify-text {
display: block;
}
.ui-pnotify-icon, .ui-pnotify-icon span {
display: block;
float: left;
margin-right: .2em;
}
/* Alternate stack initial positioning. */
.ui-pnotify.stack-topleft, .ui-pnotify.stack-bottomleft {
left: 25px;
right: auto;
}
.ui-pnotify.stack-bottomright, .ui-pnotify.stack-bottomleft {
bottom: 25px;
top: auto;
}
.ui-pnotify.stack-modal {
left: 50%;
right: auto;
margin-left: -150px;
}
@@ -1,10 +1,10 @@
import React from 'react';
import { groupBy, sortBy } from 'lodash';
import { useQuery } from '@apollo/react-hooks';
import { GET_ALIASES, GET_DOMAINS } from '../queries';
import AliasList from './AliasList';
import AliasListCreate from './AliasListCreate';
import { groupBy } from '../utils';
const MainArea = ({ query, selectedOrgUnit, orgUnits }) => {
const { data, loading, error } = useQuery(GET_ALIASES);
@@ -23,8 +23,8 @@ const MainArea = ({ query, selectedOrgUnit, orgUnits }) => {
const domain = domainData.domains[0];
const lists = groupBy(
sortBy(data.aliases, (alias) => alias.source),
(alias) => alias.source
data.aliases.sort((a, b) => a.source.localeCompare(b.source)),
'source'
);
const listPrefixes = selectedOrgUnit && orgUnits.find(({ id }) => id === selectedOrgUnit).prefixesRegex;
-1
View File
@@ -6,7 +6,6 @@ import React from 'react';
import { render } from 'react-dom';
import './index.scss';
import '@fortawesome/fontawesome-free/css/all.css';
import App from './App';
-461
View File
@@ -1,461 +0,0 @@
/* global moment, _, $, queryString, nunjucks, notify */
import { parseEmails, setQueryString } from './utils';
const API_URL = {
ALIASES: '/api/aliases/',
OU_LIST: '/api/orgunits/',
ME: '/api/me/',
EMAIL_DOMAIN: '/api/emaildomain/'
};
let csrfToken;
function filterLists(queryTerm, withMembers) {
const lists = $('.fwdlist').not('.new-list');
if ($.trim(queryTerm) === '') {
$(lists)
.find('.alias-row')
.removeClass('highlight');
$(lists).removeClass('hidden');
return;
}
/* Filter lists */
const reTerm = new RegExp(queryTerm);
lists.each(function() {
const listName = $(this).attr('data-list-name');
const members = $(this).find('.js-destination');
let hits = 0;
if (withMembers) {
hits = _.filter(members, function(el) {
const matches = reTerm.test($(el).text());
if (matches) {
$(el)
.parent()
.parent()
.addClass('highlight');
} else {
$(el)
.parent()
.parent()
.removeClass('highlight');
}
return matches;
});
} else {
$('.alias-row').removeClass('highlight');
}
if (reTerm.test(listName) || (hits.length !== 0 && withMembers)) {
$(this).removeClass('hidden');
} else {
$(this).addClass('hidden');
}
});
}
function filterListsByOrgUnit(id, prefix) {
if (!prefix) {
prefix = $(`.orgunit-list a[data-id="${id}"]`).attr('data-prefix');
}
// eslint-disable-next-line no-use-before-define
setActiveOrgUnit(id);
filterLists(prefix);
let queryParams = { orgunit: id };
if (id === '') {
queryParams = null;
}
setQueryString(queryParams);
}
function updateNumEmails(event) {
const el = $(event.target);
const emails = parseEmails(el.val());
const listName = el.attr('data-list-name');
const counter = $(`.fwdlist[data-list-name="${listName}"] .email-counter`);
if (emails.length > 0) {
counter.text(emails.length);
} else {
counter.text('');
}
}
function createAliases(newAliases, onSuccess, onError) {
$.ajax({
url: API_URL.ALIASES,
type: 'POST',
headers: { 'X-CSRFToken': csrfToken },
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(newAliases),
success: onSuccess,
error: onError
});
}
function setActiveOrgUnit(id) {
/* Reset active */
$('.orgunit-list li').removeClass('active');
/* Set current */
const orgUnit = $(`.orgunit-list li a[data-id="${id}"]`);
orgUnit.parent().toggleClass('active');
$('.orgunits-select').val(id); // <select>
/* Reset search field */
$('.js-lists-filter-field').val('');
}
function setPrefixesRegex(ous) {
ous = _.map(ous, function(ou) {
const prefixes = _.map(ou.prefixes, function(prefix) {
return `^${prefix}-|^${prefix}@`;
});
ou.prefixes_regex = prefixes.join('|');
return ou;
});
return ous;
}
function resetActiveOrgUnit() {
$('.orgunit-list li').removeClass('active');
$('.orgunit-list li:first-child').toggleClass('active');
}
$(document).ready(function() {
csrfToken = $('meta[name=x-csrf-token]').attr('content');
const forwardsContainer = $('.forwards-container');
nunjucks.configure({ autoescape: true });
moment.locale('nb');
/* Add filter |datefromnow and |date to nunjucks */
const nunjucksEnv = new nunjucks.Environment();
nunjucksEnv.addFilter('datefromnow', function(str) {
return moment(str).fromNow();
});
nunjucksEnv.addFilter('date', function(str, strformat) {
return moment(str).format(strformat);
});
/* Lists view (home) */
if ($('body.home').length) {
$('.js-lists-filter-field').focus();
/* Load orgunits */
$.getJSON(API_URL.OU_LIST, function(data) {
data = setPrefixesRegex(data);
const ouHtml = nunjucksEnv.render('orgunits.html', { orgunits: data });
$('.orgunit-list').append(ouHtml);
const ousHtml = nunjucksEnv.render('orgunits_select.html', { orgunits: data });
$('.orgunit-select-container').html(ousHtml);
/* If searching then set q */
const qs = queryString.parse(window.location.search);
if (qs.q) {
resetActiveOrgUnit();
$('.js-lists-filter-field').val(qs.q);
}
if (qs.orgunit) {
setActiveOrgUnit(qs.orgunit);
}
/* Load email domain */
$.getJSON(API_URL.EMAIL_DOMAIN, function(emailDomain) {
emailDomain = emailDomain.domain;
/* New list */
const newListHtml = nunjucksEnv.render('new_list.html', {
orgunits: data,
api_urls: API_URL,
email_domain: emailDomain
});
$('.new-list').html(newListHtml);
/* New list: List name (source) */
$('.new-list .js-new-list-name').on('keyup', function() {
let newListName = $('.new-list .js-new-list-name')
.val()
.trim();
if (newListName === '') {
$('.js-new-list-preview').html('Ny liste');
return;
}
const prefix = $('.new-list .prefix-select .active').attr('data-value');
const source = `${prefix + newListName}@${emailDomain.name}`;
let labelHtml = '<span class="label label-success">Ny</span> ';
const existingList = $(`.fwdlist[data-list-name="${source}"]`).length;
if (existingList) {
labelHtml = '<span class="label label-primary">Eksisterende</span> ';
}
newListName = labelHtml + source;
$('.js-new-list-preview').html(newListName);
});
/* New list: Select prefix */
$('.new-list .prefix-select a').on('click', function() {
$('.new-list .prefix-select a')
.parent()
.removeClass('active');
$(this)
.parent()
.addClass('active');
const prefix = $(this)
.parent()
.attr('data-value');
$('.new-list .prefix-btn').html(`${prefix} <span class="caret"></span>`);
});
$('.new-list textarea').on('keyup', updateNumEmails);
/* New list: Add list with aliases */
$('.js-add-list').on('click', function(e) {
e.preventDefault();
/* Validate */
const newListName = $('.new-list .js-new-list-name').val();
if (newListName.length === 0) {
notify('Ny epostliste', 'Navn på epostliste mangler', 'error');
return;
}
const text = $('.new-list textarea').val();
const emails = parseEmails(text);
if (emails.length === 0) {
notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error');
return;
}
// Valid form
const prefix = $('.new-list .prefix-select .active').attr('data-value');
const source = `${prefix + newListName}@${emailDomain.name}`;
const newAliases = _.map(emails, function(el) {
return {
source,
destination: el,
domain: emailDomain.id
};
});
createAliases(
newAliases,
function(aliases) {
$('.new-list textarea').val('');
$('.new-list .js-new-list-name').val('');
$('.js-new-list-preview').html('Ny liste');
$('.new-list .email-counter').html('');
const listName = aliases[0].source;
const listEl = $(`.fwdlist[data-list-name="${listName}"]`);
if (listEl.length) {
/* Append to existing list */
notify('Oppdatert', `Oppdatert: ${listName} er oppdatert`, 'success');
const listHtml = nunjucksEnv.render('aliases.html', { aliases });
listEl
.find('tbody .alias-row')
.last()
.after(listHtml);
return;
}
/* Add new list on top */
notify('Lagt til', `Ny liste: ${listName} lagt til`, 'success');
const newList = _.groupBy(aliases, function(alias) {
return alias.source;
});
const addedListHtml = nunjucksEnv.render('list.html', { lists: newList });
forwardsContainer.prepend(addedListHtml);
},
function(xhr) {
const error = xhr.responseJSON;
const msg = error && error[0].non_field_errors ? error[0].non_field_errors[0] : '';
notify('Ikke oppdatert', `Kunne ikke legge til nye eposter.\n${msg}`, 'error');
}
);
});
/* Filter lists by orgunit */
$('.orgunit-list a').on('click', function(e) {
e.preventDefault();
const id = $(this).attr('data-id');
const prefix = $(this).attr('data-prefix');
filterListsByOrgUnit(id, prefix);
});
$('.orgunits-select').on('change', function() {
const id = $(this).val();
const prefix = $(this)
.find(':selected')
.attr('data-prefix');
filterListsByOrgUnit(id, prefix);
});
});
});
/* Load forwards from API and put on page */
$.getJSON(API_URL.ALIASES, function(data) {
let errMsg;
if (data && data.length === 0) {
errMsg = 'Fant ingen tilhørende lister';
notify('Ingen lister.', errMsg, 'info');
forwardsContainer.html(errMsg);
return;
}
if (data && 'error' in data) {
errMsg = `Klarte ikke hente epostlister fra APIet: ${data.error}`;
notify('Oops!', errMsg, 'error');
forwardsContainer.html(errMsg);
return;
}
let lists = _.sortBy(data, function(alias) {
return alias.source;
});
lists = _.groupBy(lists, function(alias) {
return alias.source;
});
const fwHtml = nunjucksEnv.render('list.html', { lists });
forwardsContainer.html(fwHtml);
/* Filter lists by search term from query string */
const qs = queryString.parse(window.location.search);
if (qs.q) {
filterLists(qs.q, true);
} else if (qs.orgunit) {
filterListsByOrgUnit(qs.orgunit);
}
});
/* Mark row red for deletion and show delete button if applicable */
forwardsContainer.on('click', '[name=fwd-delete]', function() {
$(this)
.parent()
.parent()
.parent()
.toggleClass('danger');
const tbody = $(this).closest('tbody');
const numSelected = tbody.find('[name=fwd-delete]:checked').length;
if (numSelected > 0) {
tbody.find('.link-del').addClass('visible');
} else {
tbody.find('.link-del').removeClass('visible');
}
});
/* Delete selected aliases */
forwardsContainer.on('click', '.js-del-selected', function() {
const listName = $(this).attr('data-delete-list-name');
const listEl = $(`.fwdlist[data-list-name="${listName}"]`);
const checked = listEl.find('[name="fwd-delete"]:checked');
const deleteThese = _.map(checked, function(el) {
return {
source: $(el).attr('data-source'),
destination: $(el).attr('data-destination'),
domain: parseInt($(el).attr('data-domain'), 10)
};
});
function success() {
const checkedFormatted = _.map(deleteThese, function(el) {
return el.destination;
}).join(', ');
checked.closest('tr').remove();
/* remove list if no more rows */
if (listEl.find('.alias-row').length === 0) {
listEl.remove();
}
listEl.find('.link-del').removeClass('visible');
notify('Slettet', checkedFormatted, 'success');
}
function error(res) {
notify('Kunne ikke slette', res.detail, 'error');
}
const data = {
type: 'DELETE',
headers: { 'X-CSRFToken': csrfToken },
url: API_URL.ALIASES,
data: JSON.stringify(deleteThese),
contentType: 'application/json; charset=utf-8',
success,
error
};
$.ajax(data);
});
/* Toggle button for add emails textarea */
forwardsContainer.on('click', '.js-toggle-email-textarea', function(e) {
e.preventDefault();
const row = $(this)
.closest('tbody')
.find('.textarea-row');
row.toggleClass('visible');
$(this)
.closest('tbody')
.find('textarea')
.focus();
});
/* Add emails to current list */
forwardsContainer.on('click', '.js-new-email', function(e) {
e.preventDefault();
const source = $(this).attr('data-list-name');
const textarea = $(`textarea[data-list-name="${source}"]`);
const emails = parseEmails(textarea.val());
if (emails.length === 0) {
notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error');
return;
}
const listEl = $(`.fwdlist[data-list-name="${source}"]`);
const newAliases = _.map(emails, function(el) {
return {
source,
destination: el,
domain: parseInt(listEl.attr('data-domain'), 10)
};
});
createAliases(
newAliases,
function(aliases) {
const aliasesFormatted = _.map(aliases, function(el) {
return el.destination;
}).join(', ');
notify(`Oppdatert ${aliases[0].source}`, `La til epostene: ${aliasesFormatted}.`, 'success');
textarea.val('');
listEl.find('.email-counter').text('');
/* Append to existing list */
const addedListHtml = nunjucksEnv.render('aliases.html', { aliases });
listEl
.find('tbody .alias-row')
.last()
.after(addedListHtml);
},
function(xhr) {
const error = xhr.responseJSON;
const msg = error && error[0].non_field_errors ? error[0].non_field_errors[0] : '';
notify('Ikke oppdatert', `Kunne ikke legge til nye eposter.\n${msg}`, 'error');
}
);
});
/* Update num emails for all list textarea's */
forwardsContainer.on('keyup', '.js-add-list-textarea, .new-list textarea', updateNumEmails);
/* Filter by search query */
$('.js-lists-filter-field').on('keyup change', function() {
const term = $(this).val();
filterLists(term, true);
resetActiveOrgUnit();
let queryParams = { q: term };
if (term === '') {
queryParams = null;
}
setQueryString(queryParams);
});
/* New list toggle display button */
$('.new-list-btn').on('click', function() {
$('.new-list').toggleClass('visible');
});
}
});
+6 -176
View File
@@ -1,178 +1,8 @@
$icon-font-path: "../fonts/";
@import "~bootstrap/scss/bootstrap";
@import "pnotify.core";
@import "./animations";
@import "./sidebar";
.login-form {
margin: 0 auto;
max-width: 300px;
float: none;
input[type=submit] {
float: right;
}
}
/* Sticky footer styles */
.footer {
margin-top: 40px;
}
/* Lists */
.del-cell {
text-align: right;
width: 54px;
padding: 2px 0 0 !important;
vertical-align: middle;
}
.del-label {
display: block;
height: 30px;
margin: 0;
text-align: center;
input {
margin: 0;
position: relative;
top: 6px;
}
}
.badge-list-total {
float: right;
position: relative;
top: 3px;
}
.new-list-btn {
margin-bottom: 1rem;
}
.new-list {
display: none;
margin-bottom: 1rem;
&.visible {
display: block;
}
}
.new-list-name {
padding-bottom: 5px;
}
.btn-add-list {
margin-top: 1rem;
}
/* Forward list */
.panel-heading {
font-weight: bold;
font-size: 16px;
}
.icon-faded {
position: relative;
top: 1px;
margin-right: 4px;
color: #ccc;
}
.table-condensed {
margin-bottom: 0;
> tbody > tr > td {
padding: 5px;
&:first-child {
padding-left: 20px;
padding-right: 20px;
}
}
> tbody > tr.action-row > td {
padding: 0;
&:first-child {
padding: 0;
}
}
}
.custom-control-label:after, .custom-control-label:before {
width: 1.3rem;
height: 1.3rem;
}
.action-row {
.link-add {
display: block;
}
.link-del {
white-space: nowrap;
display: none;
&.visible {
display: block;
}
}
a {
padding: 10px;
padding-left: 16px;
&:hover {
background-color: #f5f5f5;
}
}
textarea {
margin-bottom: 8px;
}
}
.textarea-row {
display: none;
td {
padding-right: 16px;
}
&.visible {
display: table-row;
}
.btn-add-list {
margin-bottom: 10px;
}
}
.highlight .alias:before {
width: 7px;
height: 7px;
border-radius: 50% 50%;
background-color: #00d000;
content: '';
display: inline-block;
position: absolute;
left: 20px;
margin-top: 7px;
}
.card-header {
font-weight: bold;
}
/* Responsive fixes */
@media(max-width: map-get($grid-breakpoints, "sm")){
.card-header {
font-size: 13px;
}
.card-header .icon-faded {
display: none;
}
td {
font-size: 13px;
}
.highlight .alias:before {
margin-top: 5px;
}
}
.love {
color: #faafba;
}
.credits {
margin-top: 25px;
margin-bottom: 25px;
text-align: center;
color: #666;
font-size: 12px;
}
@import "./styles/animations";
@import "./styles/mainarea";
@import "./styles/sidebar";
@import "./styles/fonts";
@import "./styles/login";
@import "./styles/footer";
@@ -0,0 +1,21 @@
$fa-font-path: "../node_modules/@fortawesome/fontawesome-free/webfonts";
@import "~@fortawesome/fontawesome-free/scss/fontawesome";
// Skip EOT and SVG fonts, ref:
// @import "~@fortawesome/fontawesome-free/scss/solid";
@font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 900;
font-display: $fa-font-display;
src: url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'),
url('#{$fa-font-path}/fa-solid-900.woff') format('woff'),
url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'),
}
.fa,
.fas {
font-family: 'Font Awesome 5 Free';
font-weight: 900;
}
Whitespace-only changes.
@@ -0,0 +1,9 @@
.login-form {
margin: 0 auto;
max-width: 300px;
float: none;
input[type=submit] {
float: right;
}
}
@@ -0,0 +1,143 @@
/* Lists */
.del-cell {
text-align: right;
width: 54px;
padding: 2px 0 0 !important;
vertical-align: middle;
}
.del-label {
display: block;
height: 30px;
margin: 0;
text-align: center;
input {
margin: 0;
position: relative;
top: 6px;
}
}
.badge-list-total {
float: right;
position: relative;
top: 3px;
}
.new-list-btn {
margin-bottom: 1rem;
}
.new-list {
display: none;
margin-bottom: 1rem;
&.visible {
display: block;
}
}
.new-list-name {
padding-bottom: 5px;
}
.btn-add-list {
margin-top: 1rem;
}
/* Forward list */
.panel-heading {
font-weight: bold;
font-size: 16px;
}
.icon-faded {
position: relative;
top: 1px;
margin-right: 4px;
color: #ccc;
}
.table-condensed {
margin-bottom: 0;
> tbody > tr > td {
padding: 5px;
&:first-child {
padding-left: 20px;
padding-right: 20px;
}
}
> tbody > tr.action-row > td {
padding: 0;
&:first-child {
padding: 0;
}
}
}
.custom-control-label:after, .custom-control-label:before {
width: 1.3rem;
height: 1.3rem;
}
.action-row {
.link-add {
display: block;
}
.link-del {
white-space: nowrap;
display: none;
&.visible {
display: block;
}
}
a {
padding: 10px;
padding-left: 16px;
&:hover {
background-color: #f5f5f5;
}
}
textarea {
margin-bottom: 8px;
}
}
.textarea-row {
display: none;
td {
padding-right: 16px;
}
&.visible {
display: table-row;
}
.btn-add-list {
margin-bottom: 10px;
}
}
.card-header {
font-weight: bold;
}
/* Responsive fixes */
@media(max-width: map-get($grid-breakpoints, "sm")){
.card-header {
font-size: 13px;
}
.card-header .icon-faded {
display: none;
}
td {
font-size: 13px;
}
}
.footer {
margin-top: 40px;
}
.love {
color: #faafba;
}
.credits {
margin-top: 25px;
margin-bottom: 25px;
text-align: center;
color: #666;
font-size: 12px;
}
@@ -1,4 +0,0 @@
<div class="alert alert-{{ alertClass }}">
<a class="close" data-dismiss="alert">×</a>
{% if iconClass %}<span class="fas fa-{{ iconClass }}"></span> {% endif %}{{ msg }}
</div>
@@ -1,8 +0,0 @@
{% for alias in aliases %}
<tr class="alias-row">
<td class="alias"><span class="js-destination" title="Lagt til {{ alias.created|datefromnow }} ({{ alias.created|date('LLLL') }})">{{ alias.destination }}</span></td>
<td class="del-cell">
<label class="del-label" for="{{alias.id}}"><input id="{{alias.id}}" type="checkbox" name='fwd-delete' value="{{alias.id}}" data-source="{{alias.source}}" data-destination="{{alias.destination}}" data-domain="{{alias.domain}}"/></label>
</td>
</tr>
{% endfor %}
@@ -1,30 +0,0 @@
{% for list,aliases in lists %}
<div class="fwdlist" data-list-name="{{ list }}" data-domain="{{aliases[0].domain}}">
<div class="panel panel-default">
<div class="panel-heading"><span class="fas fa-list-alt icon-faded" aria-hidden="true"></span> {{ list }} <span class="badge badge-list-total">{{aliases|length}}</span></div>
<table class="table table-condensed">
<tbody>
<!-- Aliases -->
{% include "aliases.html" %}
<!-- Actions: Add/Remove -->
<tr class="action-row">
<td>
<a href="#" class="link-add js-toggle-email-textarea"><span class="fas fa-plus" aria-hidden="true"></span> Legg til</a>
</td>
<td>
<a href="#" class="link-del js-del-selected" type="button" data-delete-list-name="{{ list }}"><span class="fas fa-remove" aria-hidden="true"></span> Slett</a>
</td>
</tr>
<tr class="textarea-row">
<td colspan="2">
<h4>Eposter <span class="badge email-counter"></span></h4>
<textarea class="form-control js-add-list-textarea" data-list-name="{{ list }}" placeholder="asdf@studentersamfundet.no, qwerty@studentersamfundet.no f.eks. Klipp og lim så mye du orker" rows="4"></textarea>
<button type="button" class="btn btn-primary btn-add-list js-new-email" data-list-name="{{list}}"><span class="fas fa-plus js-new-email" aria-hidden="true"></span> Legg til</button>
</td>
</tr>
</tbody>
</table>
<div class="result-alert"></div>
</div>
</div>
{% endfor %}
@@ -1,23 +0,0 @@
<div class="panel panel-default">
<div class="panel-heading"><span class="fas fa-list-alt icon-faded" aria-hidden="true"></span> <span class="js-new-list-preview">Ny liste</span></div>
<div class="panel-body">
<div class="input-group">
<span class="input-group-btn">
<button type="button" class="btn btn-default prefix-btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ orgunits[0].prefixes[0] }}- <span class="caret"></span></button>
<ul class="dropdown-menu prefix-select">
{% set first = true %}
{% for ou in orgunits %}
{% for prefix in ou.prefixes %}
<li{% if first %} class="active"{% set first = false %}{% endif %} data-value="{{ prefix }}-"><a href="#">{{prefix}}-</a></li>
{% endfor %}
{% endfor %}
</ul>
</span>
<input type="text" class="form-control js-new-list-name">
<span class="input-group-addon">@{{email_domain.name}}</span>
</div>
<h4>Eposter <span class="badge email-counter"></span></h4>
<textarea class="form-control" data-list-name='newlist@example.com' placeholder="asdf@studentersamfundet.no, qwerty@studentersamfundet.no f.eks. Klipp og lim så mye du orker" rows="4"></textarea>
<button type="button" class="btn btn-primary btn-add-list js-add-list"><span class="fas fa-plus js-add-list" aria-hidden="true"></span> Opprett liste</button>
</div>
</div>
@@ -1,4 +0,0 @@
<li class="active"><a href="/lists/" data-id="" data-prefix=".+">Alle</a></li>
{% for ou in orgunits %}
<li><a href="/lists/?orgunit={{ ou.id }}" data-prefix="{{ ou.prefixes_regex }}" data-id="{{ ou.id }}">{{ ou.name }}</a></li>
{% endfor %}
@@ -1,6 +0,0 @@
<select class="orgunits-select form-control">
<option value="" data-prefix=".+">Alle</option>
{% for ou in orgunits %}
<option value="{{ ou.id }}" data-prefix="{{ou.prefixes_regex }}">{{ ou.name }}</option>
{% endfor %}
</select>
+17 -6
View File
@@ -1,6 +1,4 @@
import PNotify from 'pnotify/dist/es/PNotify';
import PNotifyButtons from 'pnotify/dist/es/PNotifyButtons';
import * as queryString from 'query-string';
export function parseEmails(text) {
if (text === undefined || text === '') {
@@ -24,11 +22,17 @@ export function parseEmails(text) {
return [...new Set(emails)];
}
export const qsStringify = (obj) => {
const str = [];
for (const prop in obj)
if (obj.hasOwnProperty(prop)) {
str.push(`${encodeURIComponent(prop)}=${encodeURIComponent(obj[prop])}`);
}
return str.join('&');
};
export function setQueryString(obj) {
let qs = '';
if (obj) {
qs = `?${queryString.stringify(obj)}`;
}
const qs = obj ? `?${qsStringify(obj)}` : '';
window.history.pushState(null, null, `/lists/${qs}`);
}
@@ -63,3 +67,10 @@ export function getCookie(name) {
}
return cookieValue;
}
export const groupBy = (xs, key) => {
return xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
+1 -5
View File
@@ -19,11 +19,7 @@ module.exports = (env, argv) => {
plugins: [
new MiniCssExtractPlugin(),
env === 'production' ? new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) : null,
env !== 'production' ? new HtmlWebpackPlugin({ template: './src/index.html' }) : null,
new webpack.ProvidePlugin({
$: 'jquery',
_: 'lodash'
})
env !== 'production' ? new HtmlWebpackPlugin({ template: './src/index.html' }) : null
].filter(Boolean),
module: {
rules: [